Class: Es::Entity

Inherits:
Object
  • Object
show all
Defined in:
lib/es.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, options) ⇒ Entity

Returns a new instance of Entity.



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/es.rb', line 355

def initialize(name, options)
  fail Es::IncorrectSpecificationError.new("Entity name is not specified.") if name.nil?
  fail Es::IncorrectSpecificationError.new("Entity name should be a string.") unless name.is_a?(String)
  fail Es::IncorrectSpecificationError.new("Entity name should not be empty.") if name.strip.empty?
  fail Es::IncorrectSpecificationError.new("File is not specified.") if options[:file].nil?
  fail Es::IncorrectSpecificationError.new("File should be a string.") unless options[:file].is_a?(String)
  fail Es::IncorrectSpecificationError.new("Fields are not specified.") if options[:fields].nil?
  fail Es::IncorrectSpecificationError.new("Entity should contain at least one field.") if options[:fields].empty?
  # fail Es::IncorrectSpecificationError.new("Entity should contain at least one recordid field.") if !options[:fields].any? {|f| f.is_recordid?}

  @name = name
  @fields = options[:fields]
  @file = options[:file]
  if options[:timeframe] && !options[:timeframe].is_a?(Array)
    @timeframes = [options[:timeframe]]
  else
    @timeframes = options[:timeframe]
  end
  @timezone = options[:timezone] || 'UTC'
  fail Es::IncorrectSpecificationError.new("Entity #{name} should not contain multiple fields with the same name.") if has_multiple_same_fields?
end

Instance Attribute Details

#fieldsObject

Returns the value of attribute fields.



323
324
325
# File 'lib/es.rb', line 323

def fields
  @fields
end

#fileObject

Returns the value of attribute file.



323
324
325
# File 'lib/es.rb', line 323

def file
  @file
end

#nameObject

Returns the value of attribute name.



323
324
325
# File 'lib/es.rb', line 323

def name
  @name
end

#timeframesObject

Returns the value of attribute timeframes.



323
324
325
# File 'lib/es.rb', line 323

def timeframes
  @timeframes
end

#timezoneObject

Returns the value of attribute timezone.



323
324
325
# File 'lib/es.rb', line 323

def timezone
  @timezone
end

Class Method Details

.create_deleted_entity(name, options = {}) ⇒ Object



325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/es.rb', line 325

def self.create_deleted_entity(name, options = {})
  compatibility_mode = options[:compatibility_mode]
  deleted_type = compatibility_mode ? "isDeleted" : "attribute"
  file = options[:file]

  e = Es::Entity.new(name, {
    :file   => file,
    :fields => [
      Es::Field.new('Timestamp', 'timestamp'),
      Es::Field.new('Id', 'recordid'),
      Es::Field.new('IsDeleted', deleted_type)
    ]
  })
end

.parse(spec) ⇒ Object



340
341
342
343
344
345
# File 'lib/es.rb', line 340

def self.parse(spec)
  entity = Entity.new(spec[:entity], {
    :file => Pathname.new(spec[:file]).expand_path.to_s,
    :fields => spec[:fields] && spec[:fields].map {|field_spec| Field.parse(field_spec)}
  })
end

.parseOldFormat(spec) ⇒ Object



347
348
349
350
351
352
# File 'lib/es.rb', line 347

def self.parseOldFormat(spec)
   entity = Entity.new(spec[:entity], {
     :file => spec[:file],
     :fields => spec[:attributes] && spec[:attributes].map {|field_spec| Field.parse(field_spec)}
   })
end

Instance Method Details

#add_field(field) ⇒ Object



473
474
475
476
# File 'lib/es.rb', line 473

def add_field(field)
  fail Es::IncorrectSpecificationError.new("There already is a field with name #{field.name} in entity #{name}") if fields.detect {|f| f.name == field.name}
  fields << field
end

#extract(pid, es_name) ⇒ Object



502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'lib/es.rb', line 502

def extract(pid, es_name)
begin
    data = GoodData.post "/gdc/projects/#{pid}/eventStore/stores/#{es_name}/readTasks", to_extract_fragment(pid, {:pretty => false}).to_json
    link = data["asyncTask"]["link"]["poll"]
    response = GoodData.get(link, :process => false)
    while response.code != 204
      GoodData.connection.retryable(:tries => 3, :on => RestClient::InternalServerError) do
        sleep 5
        response = GoodData.get(link, :process => false)
      end
      response = GoodData.get(link, :process => false)
    end
    puts "Done downloading"
    web_dav_file = Es::Helpers.extract_destination_dir(pid, self) + '/' + Es::Helpers.destination_file(self)
    puts "Grabbing from web dav"
    GoodData.connection.download web_dav_file, file
    puts "Done"
  rescue RestClient::RequestFailed => error
    begin
      doc = Yajl::Parser.parse(error.response, :symbolize_keys => true)
    rescue Yajl::ParseError => e
      puts "Error parsing \"#{error.response}\""
    end
    pp doc
    raise error
  end
end

#get_field(name) ⇒ Object



469
470
471
# File 'lib/es.rb', line 469

def get_field(name)
  fields.detect {|f| f.name == name}
end

#has_field?(name) ⇒ Boolean

Returns:

  • (Boolean)


465
466
467
# File 'lib/es.rb', line 465

def has_field?(name)
  !!fields.detect {|f| f.name == name}
end

#has_multiple_same_fields?Boolean

Returns:

  • (Boolean)


377
378
379
# File 'lib/es.rb', line 377

def has_multiple_same_fields?
  fields.uniq_by {|s| s.name}.count != fields.count
end

#load(pid, es_name) ⇒ Object



478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/es.rb', line 478

def load(pid, es_name)
  begin
    GoodData.connection.upload file, Es::Helpers.load_destination_dir(pid, self)
    data = GoodData.post "/gdc/projects/#{pid}/eventStore/stores/#{es_name}/uploadTasks", to_load_fragment(pid).to_json
    link = data["asyncTask"]["link"]["poll"]
    response = GoodData.get(link, :process => false)
    while response.code != 204
      sleep 5
      GoodData.connection.retryable(:tries => 3, :on => RestClient::InternalServerError) do
        sleep 5
        response = GoodData.get(link, :process => false)
      end
    end
  rescue RestClient::RequestFailed => error
    begin
      doc = Yajl::Parser.parse(error.response, :symbolize_keys => true)
    rescue Yajl::ParseError => e
      puts "Error parsing \"#{error.response}\""
    end
    pp doc
    raise error
  end
end

#to_config_generatorObject



439
440
441
442
443
444
445
# File 'lib/es.rb', line 439

def to_config_generator
  {
    :entity => name,
    :file => file,
    :fields => fields.map {|f| f.to_config_generator}
  }
end

#to_extract_configObject



448
449
450
451
452
453
454
455
456
457
# File 'lib/es.rb', line 448

def to_extract_config
  {
    :timezone => timezone,
    :entities => [{
      :entity   => name,
      :file     => file,
      :fields   => fields.map {|f| f.name}
    }]
  }
end

#to_extract_configurationObject



407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/es.rb', line 407

def to_extract_configuration
  d = ActiveSupport::OrderedHash.new
  d['entity'] = name
  d['file'] = "data/estore-out/#{file.match(/[^\/]*.csv/)[0]}"
  d['fields'] =  (fields.map do |field|
   field.to_config_generator_extract
                      end)
  d['timeframes'] = (timeframes.map{|t| t.to_config_generator_extract})
  final = ActiveSupport::OrderedHash.new
  final['entities'] = [ d ]
  final
end

#to_extract_fragment(pid, options = {}) ⇒ Object



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/es.rb', line 381

def to_extract_fragment(pid, options = {})
  populates_element = (fields.find {|f| f.is_hid?} || fields.find {|f| f.is_recordid?} || fields.find {|f| f.is_autoincrement?})
  fail "Needs to have at least on ID element. Use Id, HID, autoincrement" if populates_element.nil?
  pretty = options[:pretty].nil? ? true : options[:pretty]
  read_map = [{
    :file       => Es::Helpers.web_dav_extract_destination_dir(pid, self) + '/' + Es::Helpers.destination_file(self),
    :populates  => populates_element.name,
    :columns    => (fields.map do |field|
      field.to_extract_fragment(pid, fields, options)
    end)
  }]


  d = ActiveSupport::OrderedHash.new
  d['entity'] = name
  d['timezone'] = timezone
  d['readMap'] = (pretty ? read_map : read_map.to_json)
  d['computedStreams'] = '[{"type":"computed","ops":[]}]'
  d['timeFrames'] = (timeframes.map{|t| t.to_extract_fragment(pid, options)})

  task = ActiveSupport::OrderedHash.new
  task['readTask'] = d
  task

end

#to_load_configObject



431
432
433
434
435
436
437
# File 'lib/es.rb', line 431

def to_load_config
  {
    :entity => name,
    :file   => file,
    :fields => fields.map {|f| f.to_load_config}
  }
end

#to_load_fragment(pid) ⇒ Object



421
422
423
424
425
426
427
428
429
# File 'lib/es.rb', line 421

def to_load_fragment(pid)
  {
    :uploadTask => {
      :entity       => name,
      :file         => Es::Helpers.web_dav_load_destination_dir(pid, self) + '/' + Es::Helpers.destination_file(self),
      :attributes   => fields.map {|f| f.to_load_fragment(pid)}
    }
  }
end

#to_tableObject



459
460
461
462
463
# File 'lib/es.rb', line 459

def to_table
  t = Terminal::Table.new :headings => [name]
  fields.map {|f| t << [f.name]}
  t
end

#truncate(pid, es_name, timestamp) ⇒ Object



530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/es.rb', line 530

def truncate(pid, es_name, timestamp)
  begin
    data = GoodData.post "/gdc/projects/#{pid}/eventStore/stores/#{es_name}/truncateTasks", {
      :truncateTask => {
        :entity     => @name,
        :timestamp  => timestamp.to_i
      }
    }
  rescue RestClient::BadRequest => error
    puts error.inspect
    raise error
  end
  link = data["asyncTask"]["link"]["poll"]
  response = GoodData.get(link, :process => false)
  while response.code != 204
    sleep 10
    response = GoodData.get(link, :process => false)
  end
end