<commit_before>
###
  A base class for all models in application.
  @example
     class Person extends BaseModel
       @attrs: ["id", "name"]

       @has_many: [Group]

       @form_name: "person-model"

       @validate:
        id:
          presence: true
          numericality: only_integers: true
        name:
          presence: true
          format: with: /^[A-Z].+/

        to_string: () ->
          "name: #{name}; id: #{id}, group count: #{@get('group').length}"

     class Group extends BaseModel
       @attrs: ["title", "person_id"]

       @belongs_to: [{model: "person", back: "id"}]

###
class BaseModel

  #@nodoc
  attrs: () ->
    @constructor.attrs || []

  #normalize model name: UserModel => user_model
  normal_name: () ->
    SiriusUtils.underscore(@constructor.name)

  #@nodoc
  has_many: () ->
    @constructor.has_many || []

  #@nodoc
  has_one: () ->
    @constructor.has_one || []

  #@nodoc
  belongs_to: () ->
    @constructor.belongs_to || [] #array with object

  validators: () ->
    @constructor.validate

  ###
    Because models contain attributes as object, this method extract only keys
    attrs : [{"id" : 1}] => after normalization ["id"]
  ###
  normalize_attrs: () ->
    for a in @constructor.attrs
      do(a) ->
        if typeof(a) is "object"
          Object.keys(a)[0]
        else
          a

  ###
    Take a object with attributes for creation;
    @note: by now not supported relations!
    @example
      class MyModel extends BaseModel
        @attrs: ["id"]

      my_model = new MyModel({id: 1})

    This methods, generate properties for object from `@attrs` array.
    Each property starts with `_`.
    Also it's generated properties for `@has_many` and `@has_one` attributes.

  ###
  constructor: (obj = {}) ->
    @_isValid = false

    # object, which contain all errors, which registers after validation
    @errors = {}
    @attributes = @normalize_attrs()

    for attr in @attrs()
      if typeof(attr) is "object"
        [key, ...] = Object.keys(attr)
        throw new Error("Attributes should have a key and value") if !key
        @["_#{key}"] = attr[key]
      else
        @["_#{attr}"] = null

    for klass in @has_many()
      #FIXME : maybe normalize class name
      @["_#{klass}"] = []
      @attributes.push("#{klass}")
      @["add_#{klass}"] = (z) =>
        name = z.constructor.name
        me   = @normal_name()
        m_name = @constructor.name

        expected = SiriusApplication.camelize(klass)
        throw new Error("Expected #{expected}, but given: #{name}") if name isnt expected
        @get("#{klass}").push(z)

        #feedback
        b_model = (for i in z.belongs_to()
          do(i) ->
            i if i['model'] == me
        )[0]

        if !b_model
          throw new Error("Model #{name} must contain '@belongs_to: [{model: #{me}, back: #{me}_id]'")

        if !(back = b_model['back'])
          throw new Error("Define 'back' property for @belongs_to")

        if @attributes.indexOf(back) == -1
          throw new Error("Foreign key: '#{back}' not contain in a '#{m_name}' model")

        key = "#{me}_#{back}"
        if z.attributes.indexOf(key) == -1
          throw new Error("Define #{key} in @attrs for '#{expected}' model")

        z.set("#{key}", @get(back))


    #TODO: refactor this
    for klass in @has_one()
      @["_#{klass}"] = null
      @attributes.push("#{klass}")
      @["add_#{klass}"] = (z) =>
        name = z.constructor.name
        me   = @normal_name()
        m_name = @constructor.name

        expected = SiriusApplication.camelize(klass)
        throw new Error("Expected #{expected}, but given: #{name}") if name isnt expected

        if @get("#{klass}")
          throw new Error("Model #{expected} already exist for #{m_name}")

        @set("#{klass}", z)

        #feedback
        b_model = (for i in z.belongs_to()
          do(i) ->
            i if i['model'] == me
        )[0]

        if !b_model
          throw new Error("Model #{name} must contain '@belongs_to: [{model: #{me}, back: #{me}_id]'")
<commit_msg>small refactor<commit_after>
###
  A base class for all models in application.
  @example
     class Person extends BaseModel
       @attrs: ["id", "name"]

       @has_many: [Group]

       @form_name: "person-model"

       @validate:
        id:
          presence: true
          numericality: only_integers: true
        name:
          presence: true
          format: with: /^[A-Z].+/

        to_string: () ->
          "name: #{name}; id: #{id}, group count: #{@get('group').length}"

     class Group extends BaseModel
       @attrs: ["title", "person_id"]

       @belongs_to: [{model: "person", back: "id"}]

###
class BaseModel

  #@nodoc
  attrs: () ->
    @constructor.attrs || []

  #normalize model name: UserModel => user_model
  normal_name: () ->
    SiriusUtils.underscore(@constructor.name)

  #@nodoc
  has_many: () ->
    @constructor.has_many || []

  #@nodoc
  has_one: () ->
    @constructor.has_one || []

  #@nodoc
  belongs_to: () ->
    @constructor.belongs_to || [] #array with object

  validators: () ->
    @constructor.validate

  ###
    Because models contain attributes as object, this method extract only keys
    attrs : [{"id" : 1}] => after normalization ["id"]
  ###
  normalize_attrs: () ->
    for a in @constructor.attrs
      do(a) ->
        if typeof(a) is "object"
          Object.keys(a)[0]
        else
          a

  ###
    Take a object with attributes for creation;
    @note: by now not supported relations!
    @example
      class MyModel extends BaseModel
        @attrs: ["id"]

      my_model = new MyModel({id: 1})

    This methods, generate properties for object from `@attrs` array.
    Each property starts with `_`.
    Also it's generated properties for `@has_many` and `@has_one` attributes.

  ###
  constructor: (obj = {}) ->
    @_isValid = false

    # object, which contain all errors, which registers after validation
    @errors = {}
    @attributes = @normalize_attrs()

    for attr in @attrs()
      if typeof(attr) is "object"
        [key, ...] = Object.keys(attr)
        throw new Error("Attributes should have a key and value") if !key
        @["_#{key}"] = attr[key]
      else
        @["_#{attr}"] = null

    for klass in @has_many()
      #FIXME : maybe normalize class name
      @["_#{klass}"] = []
      @attributes.push("#{klass}")
      @["add_#{klass}"] = (z) =>
        name = z.constructor.name
        me   = @normal_name()
        m_name = @constructor.name

        expected = SiriusApplication.camelize(klass)
        throw new Error("Expected #{expected}, but given: #{name}") if name isnt expected
        @get("#{klass}").push(z)

        #feedback
        b_model = (for i in z.belongs_to() when i['model'] == me then i)[0]

        if !b_model
          throw new Error("Model #{name} must contain '@belongs_to: [{model: #{me}, back: #{me}_id]'")

        if !(back = b_model['back'])
          throw new Error("Define 'back' property for @belongs_to")

        if @attributes.indexOf(back) == -1
          throw new Error("Foreign key: '#{back}' not contain in a '#{m_name}' model")

        key = "#{me}_#{back}"
        if z.attributes.indexOf(key) == -1
          throw new Error("Define #{key} in @attrs for '#{expected}' model")

        z.set("#{key}", @get(back))


    #TODO: refactor this
    for klass in @has_one()
      @["_#{klass}"] = null
      @attributes.push("#{klass}")
      @["add_#{klass}"] = (z) =>
        name = z.constructor.name
        me   = @normal_name()
        m_name = @constructor.name

        expected = SiriusApplication.camelize(klass)
        throw new Error("Expected #{expected}, but given: #{name}") if name isnt expected

        if @get("#{klass}")
          throw new Error("Model #{expected} already exist for #{m_name}")

        @set("#{klass}", z)

        #feedback
        b_model = (for i in z.belongs_to() when i['model'] == me then i)[0]

        if !b_model
          throw new Error("Model #{name} must contain '@belongs_to: [{model: #{me}, back: #{me}_id]'")

{'fraction_non_alphanumeric': 0.15712350695727126, 'fraction_numerical': 0.001723925624923039, 'mean_word_length': 2.3396381578947367, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 33, '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': '5793021', 'n_tokens_mistral': 2561, 'n_tokens_neox': 2528, 'n_words': 727}