Perl:如何为通过 ajax/json 传递的 DBIx::Class 查询信息包含标量引用

Perl: How to include scalar reference for DBIx::Class query information passed with ajax/json

我有一个查询要从 jquery/ajax/json 传递到将使用 DBIx::Class 和 return 结果执行的 perl 脚本。我可以让基本查询正常工作,但是当我必须包含标量引用时 运行 遇到了麻烦。我对我在这里所做的所有概念的理解有点松散,所以请原谅任何不准确的地方。

这里是我定义传递给 perl 脚本的查询参数的地方:

var jsonData = $.ajax({
  url: 'cgi-bin/getdata.cgi',
  data: JSON.stringify({
    table: 'Processes',
    search: {
      query_server:'SERVER1',
      query_time: {
        '>=':'now() - INTERVAL 1 DAY'
      }
    },
    attrib: {
      select: [
        'query_time',
        {avg:'bytes_processed'}
      ],
      order_by: 'query_time',
      group_by: 'query_time'
    }
  }),
  contentType: "application/json",
  dataType: 'json',
  method: 'POST',
  async: false
}).responseText;

这是 perl 脚本的一部分,它读取标准输入,从 json 转换并运行查询:

while ( <STDIN> )
{
  $json .= $_;
}

my $query = from_json($json);

my $table = $query->{'table'};
my $search = $query->{'search'};
my $attrib= $query->{'attrib'};

print "Table:\n" . Dumper($table) . "\n";
print "Search:\n" . Dumper($search) . "\n";
print "Attrib:\n" . Dumper($attrib) . "\n";

my $retSet = $schema->resultset($table)->search( $search, $attrib );
my $retRow = $retSet->next;

这是我得到的输出(启用 DBIC_TRACE):

Table:
$VAR1 = 'Processes';

Search:
$VAR1 = {
          'query_time' => {
                            '>=' => 'now() - INTERVAL 1 DAY'
                          },
          'query_server' => 'SERVER1'
        };

Attrib:
$VAR1 = {
          'order_by' => 'query_time',
          'group_by' => 'query_time',
          'select' => [
                        'query_time',
                        {
                          'avg' => 'bytes_processed'
                        }
                      ]
        };

SELECT me.query_time, AVG( bytes_processed ) FROM processes me WHERE ( ( query_server = ? AND query_time >= ? ) ) GROUP BY query_time ORDER BY query_time: 'TSMCORP6', 'now() - INTERVAL 1 DAY'

问题是 'now() - INTERVAL 1 DAY' 值需要是标量引用才能正确执行查询。如果我在 perl 脚本中构建查询(而不是从 html 文件传递​​),如下所示:

my $search = {
  query_server => 'SERVER1',
  query_time   => {
    '>=' => \'now() - INTERVAL 1 DAY'
  }
};

然后搜索数据看起来像这样并按照我想要的方式执行:

Search:
$VAR1 = {
          'query_time' => {
                            '>=' => \'now() - INTERVAL 1 DAY'
                          },
          'query_server' => 'SERVER1'
        };
...
SELECT me.query_time, AVG( bytes_processed ) FROM processes me WHERE ( ( query_server = ? AND query_time >= now() - INTERVAL 1 DAY ) ) GROUP BY query_time ORDER BY query_time: 'TSMCORP6'

根据我的理解,我认为将值作为引用传递没有任何意义,所以我试图了解如何在 perl 脚本中 "convert" 它。我试过在 from_json 处理之前加入反斜杠,但这没有用。非常感谢您的帮助!

更新:我能够使用以下代码将值转换为引用。但是,这行得通,因为我知道需要将什么值转换为引用。在正常情况下,该值可以在数据结构中的任何位置。我可以用 !ref! 之类的东西标记该值,然后搜索整个数据结构并转换我找到的每一个吗?那看起来怎么样?

my $cond = $query->{'search'}->{'query_time'}->{'>='};
$query->{'search'}->{'query_time'}->{'>='}=$cond;

问题是 JSON 没有任何内容可以清楚地映射到引用类型,因为它只是数据。但是,我认为您在预处理传入数据并将文字 SQL 转换为 DBIC 期望的引用方面走在了正确的轨道上。在发送方,您可以向需要特殊处理的对象添加一个 literal_sql 标志,然后您可以使用 filter_json_object 找到那些键,删除它们,并创建标量字符串引用。

use strict;
use warnings;

use Data::Dump;
use JSON;

my $json = <<'EOF';
{
    "table": "Processes",
    "search": {
        "query_server": "SERVER1",
        "query_time": {
            ">=": "now() - INTERVAL 1 DAY",
            "literal_sql": true
        }
    },
    "attrib": {
        "select": [
            "query_time", {
                "avg": "bytes_processed"
            }
        ],
        "order_by": "query_time",
        "group_by": "query_time"
    }
}
EOF

my $query = JSON
    ->new
    ->filter_json_object (sub {
        my $obj = shift;
        return unless $obj->{literal_sql};
        delete($obj->{literal_sql});

        my ($key, $val) = each(%$obj);
        $obj->{$key} = \"$val";
        return $obj;
    })
    ->decode($json);

dd($query);

输出:

{
  attrib => {
              group_by => "query_time",
              order_by => "query_time",
              select   => ["query_time", { avg => "bytes_processed" }],
            },
  search => {
              query_server => "SERVER1",
              query_time   => { ">=" => \"now() - INTERVAL 1 DAY" },
            },
  table  => "Processes",
}