<commit_before>require "timeseries/version"
require "mongo_mapper"

module Timeseries
  RESOLUTIONS = [:raw, :year, :month, :week, :day]
  RAW = 0
  YEAR = 1
  MONTH = 2
  WEEK = 3
  DAY = 4

  class ResolutionProcessorYear
    def self.interval
      1.year
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year)
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  class ResolutionProcessorMonth
    def self.interval
      1.month
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year, previous_time.month)
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  class ResolutionProcessorWeek
    def self.interval
      7.days
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year, previous_time.month, previous_time.day) - previous_time.wday.days
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  class ResolutionProcessorDay
    def self.interval
      1.day
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year, previous_time.month, previous_time.day)
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  ResolutionProcessors = [nil, ResolutionProcessorYear, ResolutionProcessorMonth, ResolutionProcessorWeek, ResolutionProcessorDay]

  class Series
    include MongoMapper::EmbeddedDocument
    belongs_to :series_collection

    key :items, Array

    def as_full_json
      items.as_json
    end
  end

  class Timeseries
    include MongoMapper::Document
    belongs_to :chronological, polymorphic: true
    after_validation :create_series

    key :name
    key :config, Hash
    key :last, Array
    many :series, order: :_id, class_name: 'Timeseries::Series', as: 'series_collection', dependent: :destroy

    # after_destroy :remove_series_documents
    def initialize(name, config = {})
      self.name = name
      self.config = {'resolution' => :day}.merge(config || {})
    end

    def create_series
      if self.series == nil || self.series.length == 0
        self.series = []
        #create one series per resolution we want to track
        (RAW..DAY).each{ |r|
          self.series << Series.new

          break if r == self.config['resolution']
        }
      end
    end

    def << (item)
      if (self.last && self.last[0] && self.last[0] >= item[0])
        raise "Add time series items in chronological order"
      end

      self.series[RAW].items << item

      # find out boundary and see if the new item crossed the boundary
      if (self.last && self.last[0]) 
        previous_time = self.last[0]
        previous_value = self.last[1]

        next_time = item[0]
        next_value = item[1]

        (1..RESOLUTIONS.length-1).each {|resolution|
          s = self.series[resolution]
          break if s == nil

          interval_processor = ResolutionProcessors[resolution]
          next unless interval_processor

          record_time = interval_processor.record_time(previous_time) + interval_processor.interval
          records_added = false

          while (record_time <= next_time)
            record_value = next_value - ((next_time - record_time)*(next_value-previous_value)) / (next_time - previous_time)
            s.items << [record_time - interval_processor.interval, record_value.to_i]

            record_time = interval_processor.next_record_time(record_time)
            records_added = true
          end
        }
      end

      self.last = item
      if chronological.send("#{self.name}_first_time") == nil
        chronological.send("#{self.name}_first_time=", item[0])
        chronological.send("#{self.name}_first_value=", item[1])
      end

      chronological.send("#{self.name}_current_time=", item[0])
      chronological.send("#{self.name}_current_value=", item[1])
      chronological.save
    end

    def query(params)
      resolution = DAY
      if (params[:r] != nil)
        resolution = Integer(params[:r])
      end

      self.series[resolution].items.as_json
    end
<commit_msg>Rename resolution param in query call<commit_after>require "timeseries/version"
require "mongo_mapper"

module Timeseries
  RESOLUTIONS = [:raw, :year, :month, :week, :day]
  RAW = 0
  YEAR = 1
  MONTH = 2
  WEEK = 3
  DAY = 4

  class ResolutionProcessorYear
    def self.interval
      1.year
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year)
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  class ResolutionProcessorMonth
    def self.interval
      1.month
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year, previous_time.month)
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  class ResolutionProcessorWeek
    def self.interval
      7.days
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year, previous_time.month, previous_time.day) - previous_time.wday.days
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  class ResolutionProcessorDay
    def self.interval
      1.day
    end

    def self.record_time(previous_time)
      Time.utc(previous_time.year, previous_time.month, previous_time.day)
    end

    def self.next_record_time(t)
      t + self.interval
    end
  end

  ResolutionProcessors = [nil, ResolutionProcessorYear, ResolutionProcessorMonth, ResolutionProcessorWeek, ResolutionProcessorDay]

  class Series
    include MongoMapper::EmbeddedDocument
    belongs_to :series_collection

    key :items, Array

    def as_full_json
      items.as_json
    end
  end

  class Timeseries
    include MongoMapper::Document
    belongs_to :chronological, polymorphic: true
    after_validation :create_series

    key :name
    key :config, Hash
    key :last, Array
    many :series, order: :_id, class_name: 'Timeseries::Series', as: 'series_collection', dependent: :destroy

    # after_destroy :remove_series_documents
    def initialize(name, config = {})
      self.name = name
      self.config = {'resolution' => :day}.merge(config || {})
    end

    def create_series
      if self.series == nil || self.series.length == 0
        self.series = []
        #create one series per resolution we want to track
        (RAW..DAY).each{ |r|
          self.series << Series.new

          break if r == self.config['resolution']
        }
      end
    end

    def << (item)
      if (self.last && self.last[0] && self.last[0] >= item[0])
        raise "Add time series items in chronological order"
      end

      self.series[RAW].items << item

      # find out boundary and see if the new item crossed the boundary
      if (self.last && self.last[0]) 
        previous_time = self.last[0]
        previous_value = self.last[1]

        next_time = item[0]
        next_value = item[1]

        (1..RESOLUTIONS.length-1).each {|resolution|
          s = self.series[resolution]
          break if s == nil

          interval_processor = ResolutionProcessors[resolution]
          next unless interval_processor

          record_time = interval_processor.record_time(previous_time) + interval_processor.interval
          records_added = false

          while (record_time <= next_time)
            record_value = next_value - ((next_time - record_time)*(next_value-previous_value)) / (next_time - previous_time)
            s.items << [record_time - interval_processor.interval, record_value.to_i]

            record_time = interval_processor.next_record_time(record_time)
            records_added = true
          end
        }
      end

      self.last = item
      if chronological.send("#{self.name}_first_time") == nil
        chronological.send("#{self.name}_first_time=", item[0])
        chronological.send("#{self.name}_first_value=", item[1])
      end

      chronological.send("#{self.name}_current_time=", item[0])
      chronological.send("#{self.name}_current_value=", item[1])
      chronological.save
    end

    def query(params)
      resolution = DAY
      if (params[:resolution] != nil)
        resolution = Integer(params[:resolution])
      end

      self.series[resolution].items.as_json
    end

{'fraction_non_alphanumeric': 0.09533026857004596, 'fraction_numerical': 0.005806919912896201, 'mean_word_length': 2.591225021720243, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1256471', 'n_tokens_mistral': 2587, 'n_tokens_neox': 2448, 'n_words': 573}