Skip to content

Instantly share code, notes, and snippets.

@homam
Last active October 19, 2016 13:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save homam/d1ec08298e99471c08cb to your computer and use it in GitHub Desktop.
Save homam/d1ec08298e99471c08cb to your computer and use it in GitHub Desktop.
CLI tool for fast and hassle-free JSON to CSV conversion
#!/usr/local/bin/lsc -d
{foldl, Str, Obj, map} = require \prelude-ls
json-to-csv = (obj) ->
cols = obj.0 |> Obj.keys
(cols |> (Str.join \,)) + "\n" + do ->
obj
|> foldl do
(acc, a) ->
acc.push <| cols |> (map (c) -> a[c]) |> Str.join \,
acc
[]
|> Str.join "\n"
stdin = process.openStdin!
code = process.argv.2
input = ""
stdin.on \data, (data) ->
input += data if data is not null
stdin.on \end, ->
process.stdout.write <| json-to-csv (JSON.parse input)
process.stdout.write "\n"
#!/usr/local/bin/lsc -d
# quote strings
{foldl, Str, Obj, map, zip} = require 'prelude-ls'
json-to-csv = (obj) ->
cols = obj.0 |> Obj.keys
colTypes = cols `zip` (cols.map (c) -> typeof! obj.0[c])
(cols |> (Str.join \,)) + "\n" + do ->
obj
|> foldl do
(acc, a) ->
acc.push <| colTypes |> (map ([c, t]) -> if t == 'String' then '"' + a[c] + '"' else a[c]) |> Str.join \,
acc
[]
|> Str.join "\n"
stdin = process.openStdin!
code = process.argv.2
input = ""
stdin.on \data, (data) ->
input += data if data is not null
stdin.on \end, ->
process.stdout.write <| json-to-csv (JSON.parse input)
process.stdout.write "\n"
#!/usr/local/bin/lsc -d
{map, filter, foldl, foldl1, id, Obj, Str, any, all, difference, unique-by, concat-map, obj-to-pairs} = require \prelude-ls
is-array = (o) -> "[object Array]" == Object.prototype.toString.call o
is-string = (o) -> "[object String]" == Object.prototype.toString.call o
is-primary = (o) ->
type = Object.prototype.toString.call o
['String', 'Number', 'Boolean'] |> map (-> "[object #it]") |> any (== type)
outer-join = (f, left, right) -->
[l `f` r for l in left for r in right]
# (a -> String -> (o -> a')) -> [{func : (o -> a'), name : String}]
keys = (o, prefix = "", selector = id) ->
return [func: selector, name: prefix] if !o or Obj.empty o or is-primary o
kvs = Obj.obj-to-pairs o
kvs |> concat-map ([k, v]) ->
keys v, (if prefix == "" then "" else prefix + "-") + k, selector >> -> it?[k]
# o -> primary-value or null
csv-cell = (s) ->
return "" if s is null
return "\"#s\"" if is-string s and (s.indexOf ' ') > -1
s
# [x] -> String
unwinded-json-to-csv = (arr) ->
all-keys = arr |> concat-map keys
max-keys = all-keys |> unique-by (.name)
values = [(max-keys |> map (.name))] ++ foldl ((acc, a) -> acc ++ [max-keys |> map (.func a)]), [], arr
values |> map (map csv-cell) >> (Str.join ',') |> Str.join "\n"
# String -> b -> o -> [unwind ... b <<< o] or b <<< o
unwind = (prefix, baggage, obj) -->
prefixify = (p, d = '-') ->
(if prefix == "" then "" else prefix + d) + p
return {} <<< baggage <<< "#prefix": obj if is-primary obj
return concat-map (unwind prefix, {} <<< baggage), obj if is-array obj
obj-keys = Obj.keys obj
array-props = obj-keys |> filter (-> is-array obj[it])
non-array-props = obj-keys `difference` array-props
non-array-object = non-array-props |> foldl ((o, p) -> o[prefixify p] = obj[p]; o), {}
return {} <<< baggage <<< non-array-object if array-props.length == 0
array-props
|> map (p) ->
obj[p] |> concat-map unwind (prefixify p), {} <<< baggage <<< non-array-object
|> foldl1 (outer-join (-> {} <<< &0 <<< &1))
json-to-csv = (obj) ->
(unwind "", {}, obj) |> unwinded-json-to-csv
stdin = process.openStdin!
code = process.argv.2
input = ""
stdin.on \data, (data) ->
input += data if data is not null
stdin.on \end, ->
process.stdout.write <| json-to-csv (JSON.parse input)
process.stdout.write "\n"
@homam
Copy link
Author

homam commented Sep 11, 2014

curl -s -u "078735bc:a6028e865466e9299cc639e944e5dbc78c0fb8cc" "https://hub.celtra.com/api/analytics?metrics=sessions,creativeLoads,creativeViews00,sessionsWithInteraction,interactions&dimensions=campaignName,creativeId,creativeName,supplierName&filters.accountDate.gte=2014-09-09&filters.accountDate.lte=2014-09-12&filters.accountId=e97de0f9&sort=-sessions&limit=200" | jqlsc "(.rows)" | jqlsc "map ( -> it  <<< ri: it.sessionsWithInteraction / it.creativeViews00)" | jqlsc "sort-by (.creativeViews00)" |  underscore print --color 

Test with

solar-system = [
  {pname: 'jupiter', mass: 5, satellites: [
    {sname: 'ganymede', color: 'orange', craters: [
      {size: 4, location: {x: 12, y: 33}, orbits: [{gamma:3, alpha: 4},{gamma: 5, alpha: -1}]}
      {size: 12, location: {x: -37, y: -55}}
      ]}
    {sname: 'europa', color: 'white'}
    {sname: 'io', color: 'red', volcanos: ['vol1', 'vol2']}
    ]}
  {pname: 'saturn', mass: 3, satellites: [
    {sname: 'titan', color: 'yellow', atmosphere: [{gas: 'Hydrogen'},{gas: 'Helium'}]}
    {sname: 'mimas', color: 'gray'}
    ]}
]

json-to-csv solar-system

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment