The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

MikroTik::Client::Query - Build MikroTik queries from perl structures

SYNOPSIS

  use MikroTik::Client::Query qw(build_query);

  # (a = 1 OR a = 2) AND (b = 3 OR c = 4 OR d = 5)
  my $query = {
      a => [1, 2],
      [
        b => 3,
        c => 4,
        d => 5
      ]
  };


  # Some bizarre nested expressions.
  # (a = 1 OR b = 2 OR (e = 5 AND f = 6 AND g = 7))
  #   OR
  # (c = 3 AND d = 4)
  #   OR
  # (h = 8 AND i = 9)
  $query = [
      -or  => {
          a => 1,
          b => 2,
          -and => {e => 5, f => 6, g => 7}
      },

      # OR
      -and => [
          c => 3,
          d => 4
      ],

      # OR
      {h => 8, i => 9}
  ];

DESCRIPTION

Simple and supposedly intuitive way to build MikroTik API queries. Following ideas of SQL::Abstract.

METHODS

build_query

  use MikroTik::Client::Query qw(build_query);

  # (type = 'ipip-tunnel' OR type = 'gre-tunnel') AND running = 'true'
  # $query
  #     = ['?type=ipip-tunnel', '?type=gre-tunnel', '?#|', '?running=true', '?#&'];
  my $query
      = build_query({type => ['ipip-tunnel', 'gre-tunnel'], running => 'true'});

Builds a query and returns an arrayref with API query words.

QUERY SYNTAX

Basic idea is that everything in arrayrefs are OR'ed and everything in hashrefs are AND'ed unless specified otherwise. Another thing is, where a value is expected, you should be able to use a list to compare against a set of values.

Key-value pairs

  # type = 'gre-tunnel' AND running = 'true'
  my $query = {type => 'gre-tunnel', running => 'true'};

  # disabled = 'true' OR running = 'false'
  $query = [disabled => 'true', running => 'false'];

Simple attribute value comparison.

List of values

  # type = 'ether' OR type = 'wlan'
  my $query = {type => ['ether', 'wlan']};

You can use arrayrefs for a list of possible values for an attribute. By default, it will be expanded into an OR statement.

Comparison operators

  # comment isn't empty (more than empty string)
  my $query = {comment => {'>', ''}};

  # mtu > 1000 AND mtu < 1500
  $query = {mtu => {'<' => 1500, '>' => 1000}};

Hashrefs can be used for specifying operator for comparison. Well, any of three of them. :) You can put multiple operator-value pairs in one hashref and they will be expanded into an AND statement.

  # mtu < 1000 OR mtu > 1500
  $query = {mtu => [{'<', 1000}, {'>', 1500}]};

  # Or like this
  # mtu < 1000 OR (mtu > 1400 AND mtu < 1500)
  $query = {mtu => [{'<', 1000}, {'>', 1400, '<', 1500}]};

Hashrefs can be also put in lists. If you want them combined into an OR statement, for example.

  # status = 'active' OR status = 'inactive'
  $query = {mtu => {'=', ['active', 'inactive']}};

Or you can use list as a value in a hashref pair. CAVEAT: In this case, every other pair in the hash will be ignored.

Negation

  # !(interface = 'ether5')
  my $query = {interface => {-not => 'ether5'}};

  # !(interface = 'ether5') AND !(interface = 'ether1')
  $query = {interface => {-not => [-and => 'ether5', 'ether1']}};

Since MikroTik API does not have 'not equal' operator, it ends up been 'opposite of a equals b' expressions.

Checking for an attribute

  my $query = {-has => 'dafault-name'};

  $query = {-has_not => 'dafault-name'};

Checks if an element has an attribute with specific name.

Literal queries

  my $query = \['?type=ether', '?running=true', '?actual-mtu=1500', '?#&&'];

  $query = [
      type => 'ipip-tunnel',
      \['?type=ether', '?running=true', '?actual-mtu=1500', '?#&&']
  ];

Reference to an arrayref can be used to pass list of prepared words. Those will be treated as blocks in nested expressions.

Logic and nesting

  # (mtu = 1460 AND actual-mtu = 1460)
  #   AND
  # (running = 'false' OR disabled = 'true')

  my $query = {
      {mtu     => 1460,    'actual-mtu' => 1460},
      [running => 'false', disabled     => 'true']
  };

Conditions can be grouped and nested if needed. It's like putting brackets around them.

  # Same thing, but with prefixes
  my $query = {
      -and => [mtu     => 1460,    'actual-mtu' => 1460],
      -or  => {running => 'false', disabled     => 'true'}
  };

You can change logic applied to a block by using keywords. Those keywords will go outside for blocks that affect multiple attributes, or ...

  # !(type = 'ether') AND !(type = 'wlan')

  # Will produce the same result
  my $query = {type => [-and => {-not => 'ether'}, {-not => 'wlan'}]};
  $query = {type => {-not => [-and => 'ether', 'wlan']}};

  # Wrong, second condition will replace first
  $query = {type => {-not => 'ether', -not => 'wlan'}};

... inside for a list of values of a single attribute.

  # This is wrong
  my $query = [
    -and =>
      {type => 'ether'},
      {running => 'true'}
  ];

  # It will actually results in
  # type = 'ether' OR running = 'true'

-and will be treated as prefix for the first hashref and, since this hash has only one element, won't affect anything at all.