Archeometer.Query (Archeometer v0.5.0)

This module exposes a from/2 macro to creates queries for the Archeometer database. The recommended way to use it is to import the whole module. Let's see a simple example!

import Archeometer.Query
alias Archeometer.Schema.Module

# then you can use it to make queries!
Archeometer.Repo.all(
  from m in Module,
    select: m.name,
    where: m.num_lines > 50
)

The first argument must be an expression in the form of m in Module, where m will be the prefix used for all the fields in the query, and Module is a module implementing Archeometer.Schema.

The available schemas are

Each schema specifies its fields and how it is related to the other schemas, like in an SQL Database!

query-keywords

Query keywords

The rest of the arguments specify how to construct the query. Each option is mapped to an SQL keyword. They are

  • :select
  • :where
  • :order_by
  • :group_by
  • :having
  • :limit

Each option accepts either an Archeometer.Query.Term expression or an Archeometer.Query.Term.Container container (tuples, lists or maps). For keyword lists and maps, the keys can be used as aliases in the rest of the query.

In the case of the order_by, they keys are used to determine the order.

import Archeometer.Query
alias Archeometer.Schema.Module

from m in Module,
  select: [app: m.app.name, avg_cc: avg(m.cc)]
  where: m.app == "archeometer"
  order_by: [desc: sum(m.num_lines)],
  group_by: m.app.name
  having: avg_cc > 5,
  limit: 10

fields-and-tables

Fields and tables

Only fields can be selected. Trying to select reference to other tables will return an error. For example

import Archeometer.Query
alias Archeometer.Schema.Module

# this will fail because `functions` is a table
from m in Module, select: m.functions

# this works because `name` is a field
from m in Module, select: m.functions.name

more-examples

More Examples

  • like operator with named columns

      iex> from f in Archeometer.Schema.Function,
      ...> select: [name: f.name, arity: f.num_args],
      ...> where: arity > 3,
      ...> where: like(f.module.name, "Kamaji.Web.%")
  • Boolean operators

      iex> from m in Archeometer.Schema.Module,
      ...> where: like(m.name, "%") > 5 and sum(m.functions.cc) > 5 or not m.num_lines < 500,
      ...> select: [m.name, m.app.name]
  • Grouping with nested aggregation

      iex> from m in Archeometer.Schema.Module,
      ...> group_by: m.id,
      ...> having: max_cc > 5,
      ...> select: [module: m.name, max_cc: max(m.functions.cc)]
    
      iex> from m in Archeometer.Schema.Module,
      ...> group_by: name,
      ...> select: [name: m.name, num_deps: count(m.out_refs.callee.name)]
    
      iex> from m in Archeometer.Schema.Module,
      ...> group_by: name,
      ...> select: [name: m.name, num_usages: count(m.in_refs.caller.name)]
  • not and is_nil

      iex> from f in Archeometer.Schema.Function,
      ...> where: not is_nil(f.coverage),
      ...> select: [f.module.name, f.name, f.num_args]
  • A more complex query

      iex> from m in Archeometer.Schema.Module,
      ...> select: [name: m.name, acc_cc: sum(m.functions.cc)],
      ...> group_by: name,
      ...> where: m.num_lines > 100 and m.coverage < 0.9,
      ...> where: not exists(m.macros.name),
      ...> order_by: [desc: acc_cc],
      ...> limit: 10

Link to this section Summary

Link to this section Functions

Link to this macro

from(arg, opts)

(macro)
Link to this function

initial_query_for(module, list)

Link to this function

intersection(result1, result2)

Link to this function

root_prefix(query)