Skip to content
This repository has been archived by the owner on Oct 14, 2020. It is now read-only.

Commit

Permalink
- added CsvImporter for SQL/Ruby
Browse files Browse the repository at this point in the history
- fixed timeout issue with services
- fixed C printing issues
  • Loading branch information
jhoffner committed Oct 17, 2016
1 parent c7c7084 commit 25e5609
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 25 deletions.
1 change: 1 addition & 0 deletions docker/ruby.docker
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ RUN gem install stuff-classifier --no-ri --no-rdoc
RUN gem install symbolic --no-ri --no-rdoc
RUN gem install unit --no-ri --no-rdoc

RUN gem install chronic --no-ri --no-rdoc

# partner packages
RUN gem install ably --no-ri --no-rdoc
Expand Down
56 changes: 55 additions & 1 deletion documentation/output_format.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,61 @@ statement, the 2nd completes the nested DESCRIBE and the 3rd completes the top l
#### <COMPLETEDIN::> Details

The value of COMPLETEDIN should be time spent executing the related statement, in milliseconds. It is not required
to support time. `<COMPLETEDIN::>` is valid on its own, and in that case it is only used to terminate the current statement.
to support time. `<COMPLETEDIN::>` is valid on its own, and in that case it is only used to terminate the current statement.

### Advanced Formatting

So far the basic formatting needed to be supported by a language has been discussed. The following
details more advanced features.

#### Advanced Format Schema
The basic `<[TAG]::>[VALUE]` tag format described previously can be expanded to support modes and labels.
This is done using the following convention: `<[TAG]:[MODE]:[LABEL]>[VALUE]`. Modes and labels are optional.

For example. To write a log message with a custom container label. You can do this: `<LOG::My Label>My log message`.
In this example, we provided a tag (required) and a label, and skipped using a mode.

#### What are modes?
A mode is used to output richer content. For example there is a TABLE mode which parses the value as JSON and renders a
table out of it.

#### Advanced Tags

##### LOG
Normally each unformatted line is considered a "LOG" message and is written to STDOUT. Visually this
output will be presented withint a Log container. Multiple log lines are grouped together automatically.

In order to access richer log output content (via modes), you will need to explicitely use a LOG tag.

##### OUT
Same as LOG, however it does not wrap the output within a container UI.

##### TAB
Should be used directly after a LOG tag. Will add a 2nd tab to the log container. Otherwise treated the
same as a LOG tag. You can add multiple tabs to a LOG container.

```
<LOG::Tab 1>This is content displayed within the first tab.<:LF:>This is a 2nd line
<TAB::Tab 2>This is content displayed within the 2nd tab.
```

#### Advanced Modes

##### TABLE
##### CHART
##### DIFF
##### MARKDOWN
##### JSON
##### HIGHLIGHT
##### SCRIPT

In this mode, the tag VALUE will be considered a URL and a script will automatically be
loaded on the page. A specific file will only be loaded once.

```
<LOG:SCRIPT:>https://raw.githubusercontent.com/name/repo/file.js
```


### Why the custom format?

Expand Down
13 changes: 7 additions & 6 deletions frameworks/c/criterion.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ ReportHook(PRE_ALL)(struct criterion_test_set *tests) {

// before the test is run
ReportHook(PRE_SUITE)(struct criterion_suite_set *set) {
printf("<DESCRIBE::>%s\n", set->suite.name);
printf("\n<DESCRIBE::>%s\n", set->suite.name);
}

// before the test is run
ReportHook(PRE_TEST)(struct criterion_test *test) {
printf("<IT::>%s\n",test->name);
printf("\n<IT::>%s\n",test->name);
}

// when an assertion is hit
ReportHook(ASSERT)(struct criterion_assert_stats *stats) {
printf("\n"); // break any lines incase printf was used
if (stats->passed) {
puts("<PASSED::>Test Passed");
} else {
Expand All @@ -39,19 +40,19 @@ ReportHook(ASSERT)(struct criterion_assert_stats *stats) {

// when a test crashes unexpectedly
ReportHook(TEST_CRASH)(struct criterion_test_stats *stats) {
puts("<FAILED::>Test Crashed");
puts("\n<FAILED::>Test Crashed");
}

// after a test ends
ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
if (stats->timed_out) {
puts("<FAILED::>Test Timedout");
puts("\n<FAILED::>Test Timed Out");
}
printf("<COMPLETEDIN::>%f\n",stats->elapsed_time*1000);
printf("\n<COMPLETEDIN::>%f\n",stats->elapsed_time*1000);
}

// after the test is run
ReportHook(POST_SUITE)(struct criterion_suite_stats *stats) {
puts("<COMPLETEDIN::>");
puts("\n<COMPLETEDIN::>");
}

47 changes: 36 additions & 11 deletions frameworks/ruby/sql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@
require 'sequel'
require "faker"
require 'active_support/core_ext/object/blank'
require 'hashie'
require_relative 'sql/csv_importer'

$sql = File.read('/home/codewarrior/solution.txt')
$sql_cleaned = $sql.gsub(/(\/\*([\s\S]*?)\*\/|--.*)/, "")
$sql_commands = $sql_cleaned.split(/; *$/).select(&:present?)

def run_sql(limit: 100, print: true)
results = $sql_commands.map do |cmd|
result = cmd.downcase.start_with?("insert") ? DB.prepare(cmd) : DB[cmd]
result.to_a.tap do |results|
if results.any? or $sql_commands.length == 1
Display.table(results.take(limit), label: "SQL Results") if print
if results.count > limit
puts "Truncated #{results.count} results to show only top 100"
end
def run_sql(limit: 100, cmds: $sql_commands, print: true)
results = cmds.map do |cmd|
(cmd.downcase.start_with?("insert") ? DB.prepare(cmd) : DB[cmd]).tap do |dataset|
if dataset.count > 0 or $sql_commands.length == 1
label = "SQL Results"
label += " (Top #{limit} of #{dataset.count})" if dataset.count > limit

Display.table(dataset.limit(limit).to_a, label: label) if print
end
end
end.select {|r| r.length > 0 }
end

results.select! {|r| r.count > 0 }

$sql_results = results.length > 1 ? results : results.first
if results.length > 1
$sql_multi = true
$sql_results = results
else
$sql_multi = false
$sql_results = results.first
end

rescue Sequel::DatabaseError => ex
msg = ex.message.gsub("SQLite3::SQLException: ", "");
Expand All @@ -29,3 +38,19 @@ def run_sql(limit: 100, print: true)
end

alias :run_query :run_sql

# useful helper for finding a specific record and wrapping it in a Hashie::Mash
def find_record(table, id)
result = DB[table].where(id: id).first
result ? Hashie::Mash.new(result) : nil
end

# loops through each sql result and returns the row as a Hashie::Mash. If multiple results were returned,
# the last result set will be used
def each_result(&block)
results = $sql_multi ? $sql_results.last : $sql_results
results.each do |result|
block.call(Hashie::Mash.new(result))
end
end

80 changes: 80 additions & 0 deletions frameworks/ruby/sql/csv_importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require 'csv'
require 'chronic'

# data importer utility
class CsvImporter
attr_reader :fields, :csv, :table, :limit, :random

def initialize(file, table, fields: {}, limit: 500, random: false)
@csv = CSV.read(file)
@table = table
@fields = fields
@limit = limit
@random = random
end

def create_schema
importer = self
DB.create_table @table do
importer.csv.first.each do |field|
if importer.fields[field]
column field, importer.fields[field]
else
String field
end
end
end
end

def convert_value(field, value)
case @fields[field]
when DateTime
Chronic.parse(value)
else
value
end
end

def import(skip_schema: false)
create_schema unless skip_schema

puts "<STATUS::>Importing #{[limit, @csv.count].min} records..."

fields = @csv.first
dataset = DB[@table]

# remove the columns row
rows = @csv.to_a.drop(1)
# randomize the rows if random is enabled
rows = rows.to_a.sample(limit) if random

rows.each.with_index do |line, row|
return if row > limit

data = {}

line.each.with_index do |value, col|
data[fields[col]] = convert_value(fields[col], value)
end

dataset.insert(data)
end
end

def self.import_sales_data(random: false, limit: 300)
importer = CsvImporter.new("/runner/sample_data/sales.csv", :sales, random: random, limit: limit, fields: {
'latitude' => Float,
'longitude' => Float
})

# TODO: figure out how to fix datetime fields for SQLite
unless defined?(Sequel::SQLite)
importer.fields.merge(
'transation_date' => DateTime,
'account_created' => DateTime,
'last_login' => DateTime
)
end
importer.import
end
end
8 changes: 4 additions & 4 deletions lib/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const startService = {
spawn("/usr/lib/postgresql/9.6/bin/pg_ctl", ['-D', '/home/codewarrior/pg', 'stop'])
});

return spawnAndWait(opts, '/usr/lib/postgresql/9.6/bin/pg_ctl', ['-D', '/home/codewarrior/pg', 'start'], 'autovacuum launcher started')
return spawnAndWait(opts, '/usr/lib/postgresql/9.6/bin/pg_ctl', ['-D', '/home/codewarrior/pg', 'start'], 'autovacuum launcher started', 200 )
},
mariadb: function(opts) {
// TODO
Expand All @@ -30,7 +30,7 @@ const startService = {
}
}

function spawnAndWait(opts, cmd, args, text, timeout) {
function spawnAndWait(opts, cmd, args, text, delay) {

return new Promise(function(resolve, reject) {

Expand All @@ -41,7 +41,7 @@ function spawnAndWait(opts, cmd, args, text, timeout) {
// console.log(str); // for debugging only

if (str && str.indexOf(text) > 0){
resolve();
setTimeout(resolve, delay || 0);
}
}

Expand All @@ -51,7 +51,7 @@ function spawnAndWait(opts, cmd, args, text, timeout) {

s.on('exit', resolve);

setTimeout(resolve, timeout || 2000);
setTimeout(resolve, 2000);
});
}

Expand Down
2 changes: 1 addition & 1 deletion sample_data/medals.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Year,City,Sport,Discipline,NOC,Event,Event gender,Medal
Year,City,Sport,Discipline,NOC,Event,Gender,Medal
1924,Chamonix,Skating,Figure skating,AUT,individual,M,Silver
1924,Chamonix,Skating,Figure skating,AUT,individual,W,Gold
1924,Chamonix,Skating,Figure skating,AUT,pairs,X,Gold
Expand Down
2 changes: 1 addition & 1 deletion sample_data/sales.csv

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion test/runners/c_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ describe('.run', function() {
done();
});
});

it('should support multiple asserts', function(done) {
runner.run({
language: 'c',
Expand Down Expand Up @@ -196,7 +197,7 @@ describe('.run', function() {
}
`
}, function(buffer) {
expect(buffer.stdout).to.contain('<FAILED::>Test Timedout');
expect(buffer.stdout).to.contain('<FAILED::>Test Timed Out');
done();
});
});
Expand Down

0 comments on commit 25e5609

Please sign in to comment.