Modern JSON processor

Would you like to parse ndjson in the terminal like this?





where { bool("muted") } max { long("size") } top 3

{"id":4880123,"size":245,"muted":true}
{"id":2392636,"size":107,"muted":true}
{"id":15843320,"size":59,"muted":true}
      
      



In our work, we often use unloads in the ndjson format. However, their analysis is difficult due to the fact that the standard tool for this is jq with its monstrous syntax that generates the following:





cat file.ndjson | jq '.tickets | map(select(.assigned_displayname=="MyNameOnApi"))' | jq '.[] | "\(.id) \(.title) \t \(.description)\n"' | sed #some after jq prettifying 
      
      



Since I don't like it, I decided to make a modern json processor with a readable DSL. What does this tool already do?





First of all, there are five sql-like control constructs available for processing:





where { /*   */ }
order { /*     */ }
min   { /*      */ }
max   { /*       */ }
top   ( /* ,    */ )
      
      



, . Kotlin, . json'. , .





5 json. :





max { long("size") } top 3 where { bool("active") },

top(5) where { !bool("active") } min { int("some") },

top(5) min { time("first") to time("last") }, // duration

where { get("arr") int (0) > 5 },

where { !get("broken") } top 3 min { get(4) get("nested") bool("flag") }
      
      



, json . , jackson:





//    jackson ,  :
get(name: String)
get(idx: String)

//       :
bool(name: String)
bool(idx: String)
int(name: String)
int(idx: String)
double(name: String)
double(idx: String)
string(name: String)
string(idx: String)
time(name: String)
time(idx: String)
      
      



?

Docker. . , . , ~/Desktop



example.ndjson



, :





docker run -v ~/Desktop:/opt -it demidko/analyze example.ndjson
      
      



! json .





dsl-, . Kotlin Kotlin . jsr223 .

, :





typealias Query = (MutableList<JsonNode>, JsonNode) -> Unit

class Action(val action: MutableList<JsonNode>.(JsonNode) -> Unit) :
  Query by { list, el ->
    list.action(el)
  }
  
infix fun Action.top(limit: Int) = Action {
  action(it)
  while (size > limit) {
    removeLast()
  }
}

fun order(comparator: Comparator<JsonNode>) = Action {
  add(it)
  sortWith(comparator)
}

infix fun Action.where(filter: JsonNode.() -> Boolean) = Action {
  if (it.filter()) {
    action(it)
  }
}
      
      



, , .





GitHub: https://github.com/demidko/analyze





! .








All Articles