1
1
mirror of https://github.com/wader/fq.git synced 2024-12-01 19:12:34 +03:00
fq/pkg/interp/query.jq
2023-07-27 13:21:04 +02:00

293 lines
5.4 KiB
Plaintext

# null
def _query_null:
{term: {type: "TermTypeNull"}};
# . -> (.)
def _query_query:
{ term:
{ type: "TermTypeQuery"
, query: .
}
};
# string
def _query_string($str):
{ term:
{ type: "TermTypeString"
, str: {str: $str}
}
};
# .
def _query_ident:
{term: {type: "TermTypeIdentity"}};
def _query_is_ident:
.term.type == "TermTypeIdentity";
# a($args...) -> b($args...)
def _query_func_rename(name):
.term.func.name = name;
# $name($args)
def _query_func($name; $args):
{ term:
{ type: "TermTypeFunc"
, func:
{ args: $args
, name: $name
}
}
};
def _query_func($name):
_query_func($name; null);
def _query_func_name:
.term.func.name;
def _query_func_args:
.term.func.args;
def _query_is_func:
.term.type == "TermTypeFunc";
def _query_is_func($name):
_query_is_func and _query_func_name == $name;
def _query_is_string:
.term.type == "TermTypeString";
def _query_string_str:
.term.str.str;
def _query_empty:
_query_func("empty");
# l | r
def _query_pipe(l; r):
{ op: "|"
, left: l
, right: r
};
# . -> [.]
def _query_array:
( . as $q
| { term:
{ type: "TermTypeArray"
, array: {}
}
}
| if $q then .term.array.query = $q end
);
# {} -> {}
def _query_object:
{ term:
{ object:
{ key_vals:
( to_entries
| map(
{ key: .key
, val: {queries: [.value]}
}
)
)
}
, type: "TermTypeObject"
}
};
# l,r
def _query_comma(l; r):
{ left: l
, op: ","
, right: r
};
# [1,2,3] -> 1,2,3
# output each query in array
def _query_commas:
if length == 0 then _query_empty
else
reduce .[1:][] as $q (
.[0];
_query_comma(.; $q)
)
end;
# . -> .[]
def _query_iter:
.term.suffix_list = [{iter: true}];
# try b catch c
def _query_try(b; c):
{ term:
{ type: "TermTypeTry"
, try:
{ body: b
, catch: c
}
}
};
def _query_try(b):
_query_try(b; null);
# last query in pipeline
def _query_pipe_last:
if .term.suffix_list then
( .term.suffix_list[-1]
| if .bind.body then
( .bind.body
| _query_pipe_last
)
end
)
elif .op == "|" then
( .right
| _query_pipe_last
)
end;
def _query_transform_pipe_last(f):
def _f:
if .term.suffix_list then
.term.suffix_list[-1] |=
if .bind.body then
.bind.body |= _f
else f
end
elif .op == "|" then
.right |= _f
else f
end;
_f;
# last term, the right most
def _query_last:
if .term.suffix_list then
( .term.suffix_list[-1]
| if .bind.body then
( .bind.body
| _query_last
)
end
)
elif .op then
( .right
| _query_last
)
end;
# TODO: rename? what to call when need to transform suffix_list
def _query_transform_last(f):
def _f:
if .term.suffix_list then
( .
| if .term.suffix_list[-1].bind.body then
.term.suffix_list[-1].bind.body |= _f
else f
end
)
elif .op then
.right |= _f
else f
end;
_f;
def _query_completion_type:
( . as $q
| _query_last
| if .index.name then
{ query:
( $q
| _query_transform_last(
del(.term.suffix_list[-1])
)
)
, type: "index"
, prefix: .index.name
}
elif .term.index.name then
{ query:
( $q
| _query_transform_last(
_query_ident
)
)
, type: "index"
, prefix: .term.index.name
}
elif .term.func then
{ query:
( $q
| _query_transform_last(
_query_ident
)
)
, type:
( .term.func.name
| if startswith("$") then "var"
else "func"
end
)
, prefix: .term.func.name
}
else
null
end
);
# TODO: simplify
def _query_completion(f):
( . as $expr
# HACK: if ends with . or $, add a dummy prefix to make the query
# valid and then trim it later
| ( if (.[-1] | . == "." or . == "$") then "a"
else ""
end
) as $probesuffix
| ($expr + $probesuffix)
| try
( try _query_fromstring
catch .error
# move directives to new root query
| . as {$meta, $imports}
| del(.meta)
| del(.imports)
| _query_completion_type
| . as $c
| if . then
( .query |=
( _query_func("map"; [
_query_pipe(.; _query_try(_query_func($c | f)))
])
| _query_pipe(.; _query_func("add")
)
| .meta = $meta
| .imports = $imports
| _query_tostring
)
| .prefix |= rtrimstr($probesuffix)
)
else
{type: "none"}
end
)
catch {type: "error", name: "", error: .}
);
# query ast to ast of quey itself, used by query rewrite/slurp
def _query_toquery:
( tojson
| _query_fromstring
);
# query rewrite helper, takes care of from/to and directives
def _query_fromtostring(f):
( _query_fromstring
# save and move directives to possible new root query
| . as {$meta, $imports}
| del(.meta)
| del(.imports)
| f
| .meta = $meta
| .imports = $imports
| _query_tostring
);