如何将存储过程中的值哈希值转换为Sequel模型实例或数据集的数组

时间:2017-05-17 17:40:58

标签: ruby postgresql sequel

存储过程从名为SETOF的表中返回行数组ACCOUNTS及其关联的续集模型Account

[1] pry(#<Psql::CalculateMasterBalancesTest>)> DB.select(Sequel.lit('*')).from{ |o| Sequel.function(:get_master_accounts, DB.row_type(:accounts, @accounts['A/1/1'].values)) }.all
=> [{:id=>1651, :parent_id=>1649, :ban=>nil, :risk=>nil, :custom_attributes=>nil, :created_at=>2017-05-17 19:33:09 +0200, :updated_at=>2017-05-17 19:33:09 +0200},
 {:id=>1649, :parent_id=>1647, :ban=>nil, :risk=>nil, :custom_attributes=>nil, :created_at=>2017-05-17 19:33:09 +0200, :updated_at=>2017-05-17 19:33:09 +0200},
 {:id=>1647, :parent_id=>nil, :ban=>"A Master", :risk=>nil, :custom_attributes=>nil, :created_at=>2017-05-17 19:33:09 +0200, :updated_at=>2017-05-17 19:33:09 +0200}]

为了使这个游戏与其他应用程序保持良好,我想将这个值哈希数组实例化为Account模型实例的数组。

如果我只是将.map{|hash| Account.new(hash)}添加到上一个表达式的末尾,我会得到一个

Sequel::MassAssignmentRestriction: id is a restricted primary key

错误。

如果我欺负这一点并手动设置ID列,那么我猜测由于persisted?逻辑,某些东西很可能会让某些东西咬我(如果可能的话,会出现一些奇怪的边缘情况)在Sequel的某个地方(我只是猜测,这是ActiveRecord发生的事情,这似乎是一个常见的设计问题),

在续集中有没有一种惯用的处理方式?

2 个答案:

答案 0 :(得分:1)

有时写一个问题会给你一个答案:

Account.from{ |o| Sequel.function(:get_ancestry, DB.row_type(:accounts, @accounts['A/1/1'].values)) }.all

作品。

实际上,这真的非常非常好,因为它的行为就像任何数据集一样,你可以加入它,“在哪里”,对它进行排序等等,一切都表现得非常好。

  DB.register_row_type(:accounts)

  def ancestry_dataset
    Account.from do |o|
      Sequel.function(:get_ancestry, DB.row_type(:accounts, values))
    end
  end

然后:

def test_me
  acc = @accounts['A/1/1']
  pd = acc.ancestry_dataset

  assert pd.is_a?(Sequel::Postgres::Dataset), 'expected a postgres dataset'

  assert_equal 2, pd.count, 'count returned funny'
  assert_equal 2, pd.all.count, 'all.count returned funny'

  assert_equal 1, pd.where(parent_id: nil).count, 'where(...).count returned funny'
  assert_equal 1, pd.where(parent_id: nil).all.count, 'where(...).all.count returned funny'

  assert_equal [:id], pd.select(:id).first.keys, 'when I restrict the select statement columns, the keys are funny'
end

没有hickups它可以很好地工作,并且是处理分层数据的一个很棒的powertool。

为了将来参考,get_ancestry功能是:

CREATE OR REPLACE FUNCTION get_ancestry(_acct Accounts)
  RETURNS SETOF Accounts AS $$

DECLARE
  cur_acct Accounts%ROWTYPE;

BEGIN
  -- we start from the parent of _acct
  SELECT INTO cur_acct *
  FROM Accounts
  WHERE id = _acct.parent_id;

  WHILE (cur_acct.id IS NOT NULL) LOOP
    RAISE NOTICE 'get_ancestry: returning %', cur_acct.id;
    RETURN NEXT cur_acct;

    SELECT INTO cur_acct *
    FROM Accounts
    WHERE id = cur_acct.parent_id;
  END LOOP;
END;
$$ LANGUAGE plpgsql;

答案 1 :(得分:0)

&#34; id是受限制的主键&#34;是因为你正在传递记录的:id

在尝试实例化新帐户之前,从值中删除:id

.select(Sequel.lit('*'))

不应该是必要的。续集会自动选择*

require 'json'
require 'sequel'

DB = Sequel.sqlite
DB.create_table :items do
  primary_key :id
  String :name
  Float :price
end
items = DB[:items]
items.insert(:name => 'abc', :price => rand * 100)

class Item < Sequel::Model(:items)
end

Item.dataset.sql
# => "SELECT * FROM `items`"