NAME

API::MikroTik::Query - Build MikroTik queries from perl structures.

SYNOPSIS

use API::MikroTik::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 API::MikroTik::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 that 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 attributes

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.