<commit_before>import 'reflect-metadata';
import * as fs from 'fs';
import * as path from 'path';
import {DataTypeAbstract, DefineOptions} from 'sequelize';
import {Model} from "../models/Model";
import {IPartialDefineAttributeColumnOptions} from "../interfaces/IPartialDefineAttributeColumnOptions";
import {inferDataType} from "../utils/data-type";
import {deepAssign} from "../utils/object";
import {IScopeOptions} from "../interfaces/IScopeOptions";
import {IFindOptions} from "../interfaces/IFindOptions";
import {getAssociationsByRelation} from "./association";
import {uniqueFilter} from "../utils/array";

const MODEL_NAME_KEY = 'sequelize:modelName';
const SCOPES_KEY = 'sequelize:scopes';
const ATTRIBUTES_KEY = 'sequelize:attributes';
const OPTIONS_KEY = 'sequelize:options';
const DEFAULT_OPTIONS: DefineOptions<any> = {
  timestamps: false
};
export const PROPERTY_LINK_TO_ORIG = '__origClass';

/**
 * Sets model name from class by storing this
 * information through reflect metadata
 */
export function setModelName(target: any, modelName: string): void {

  Reflect.defineMetadata(MODEL_NAME_KEY, modelName, target);
}

/**
 * Returns model name from class by restoring this
 * information from reflect metadata
 */
export function getModelName(target: any): string {

  return Reflect.getMetadata(MODEL_NAME_KEY, target);
}

/**
 * Returns model attributes from class by restoring this
 * information from reflect metadata
 */
export function getAttributes(target: any): any|undefined {

  const attributes = Reflect.getMetadata(ATTRIBUTES_KEY, target);

  if (attributes) {

    return Object.keys(attributes).reduce((copy, key) => {

      copy[key] = Object.assign({}, attributes[key]);

      return copy;
    }, {});
  }
}

/**
 * Sets attributes
 */
export function setAttributes(target: any, attributes: any): void {

  Reflect.defineMetadata(ATTRIBUTES_KEY, Object.assign({}, attributes), target);
}

/**
 * Adds model attribute by specified property name and
 * sequelize attribute options and stores this information
 * through reflect metadata
 */
export function addAttribute(target: any,
                             name: string,
                             options: any): void {

  let attributes = getAttributes(target);

  if (!attributes) {
    attributes = {};
  }
  attributes[name] = Object.assign({}, options);

  setAttributes(target, attributes);
}

/**
 * Adds attribute options for specific attribute
 */
export function addAttributeOptions(target: any,
                                    propertyName: string,
                                    options: IPartialDefineAttributeColumnOptions): void {

  const attributes = getAttributes(target);

  if (!attributes || !attributes[propertyName]) {
    throw new Error(`@Column annotation is missing for "${propertyName}" of class "${target.constructor.name}"` +
      ` or annotation order is wrong.`);
  }

  attributes[propertyName] = deepAssign(attributes[propertyName], options);

  setAttributes(target, attributes);
}

/**
 * Returns sequelize define options from class prototype
 * by restoring this information from reflect metadata
 */
export function getOptions(target: any): DefineOptions<any>|undefined {

  const options = Reflect.getMetadata(OPTIONS_KEY, target);

  if (options) {
    return Object.assign({}, options);
  }
}

/**
 * Sets seuqlize define options to class prototype
 */
export function setOptions(target: any, options: DefineOptions<any>): void {

  Reflect.defineMetadata(OPTIONS_KEY, Object.assign({}, DEFAULT_OPTIONS, options), target);
}

/**
 * Adds options be assigning new options to old one
 */
export function addOptions(target: any, options: DefineOptions<any>): void {

  let _options = getOptions(target);

  if (!_options) {
    _options = {};
  }

  setOptions(target, Object.assign(_options, options));
}

/**
 * Maps design types to sequelize data types;
 * @throws if design type cannot be automatically mapped to
 * a sequelize data type
 */
export function getSequelizeTypeByDesignType(target: any, propertyName: string): DataTypeAbstract {

  const type = Reflect.getMetadata('design:type', target, propertyName);
  const dataType = inferDataType(type);

  if (dataType) {

    return dataType;
  }

  throw new Error(`Specified type of property '${propertyName}'
            cannot be automatically resolved to a sequelize data type. Please
            define the data type manually`);
}

/**
 * Determines models from value
 */
export function getModels(arg: Array<typeof Model|string>): Array<typeof Model> {

  if (arg && typeof arg[0] === 'string') {

    return arg.reduce((models: any[], dir) => {

      const _models = fs
        .readdirSync(dir as string)
        .filter(file => {
          const extension = file.slice(-3);
          return extension === '.js' || (extension === '.ts' && file.slice(-4) !== '.d.ts');
        })
        .map(file => path.parse(file).name)
        .filter(uniqueFilter)
        .map(fileName => {
          const fullPath = path.join(dir, fileName);
          const module = require(fullPath);

          if (!module[fileName] && !module.default) {
            throw new Error(`No default export defined for file "${fileName}" or export does not satisfy filename.`);
          }
          return module[fileName] || module.default;
        });

      models.push(..._models);

      return models;
    }, [])
      ;
  }

  return arg as Array<typeof Model>;
}
<commit_msg>Acutally commit change to fix broken test - need 5 characters for .d.ts extension<commit_after>import 'reflect-metadata';
import * as fs from 'fs';
import * as path from 'path';
import {DataTypeAbstract, DefineOptions} from 'sequelize';
import {Model} from "../models/Model";
import {IPartialDefineAttributeColumnOptions} from "../interfaces/IPartialDefineAttributeColumnOptions";
import {inferDataType} from "../utils/data-type";
import {deepAssign} from "../utils/object";
import {IScopeOptions} from "../interfaces/IScopeOptions";
import {IFindOptions} from "../interfaces/IFindOptions";
import {getAssociationsByRelation} from "./association";
import {uniqueFilter} from "../utils/array";

const MODEL_NAME_KEY = 'sequelize:modelName';
const SCOPES_KEY = 'sequelize:scopes';
const ATTRIBUTES_KEY = 'sequelize:attributes';
const OPTIONS_KEY = 'sequelize:options';
const DEFAULT_OPTIONS: DefineOptions<any> = {
  timestamps: false
};
export const PROPERTY_LINK_TO_ORIG = '__origClass';

/**
 * Sets model name from class by storing this
 * information through reflect metadata
 */
export function setModelName(target: any, modelName: string): void {

  Reflect.defineMetadata(MODEL_NAME_KEY, modelName, target);
}

/**
 * Returns model name from class by restoring this
 * information from reflect metadata
 */
export function getModelName(target: any): string {

  return Reflect.getMetadata(MODEL_NAME_KEY, target);
}

/**
 * Returns model attributes from class by restoring this
 * information from reflect metadata
 */
export function getAttributes(target: any): any|undefined {

  const attributes = Reflect.getMetadata(ATTRIBUTES_KEY, target);

  if (attributes) {

    return Object.keys(attributes).reduce((copy, key) => {

      copy[key] = Object.assign({}, attributes[key]);

      return copy;
    }, {});
  }
}

/**
 * Sets attributes
 */
export function setAttributes(target: any, attributes: any): void {

  Reflect.defineMetadata(ATTRIBUTES_KEY, Object.assign({}, attributes), target);
}

/**
 * Adds model attribute by specified property name and
 * sequelize attribute options and stores this information
 * through reflect metadata
 */
export function addAttribute(target: any,
                             name: string,
                             options: any): void {

  let attributes = getAttributes(target);

  if (!attributes) {
    attributes = {};
  }
  attributes[name] = Object.assign({}, options);

  setAttributes(target, attributes);
}

/**
 * Adds attribute options for specific attribute
 */
export function addAttributeOptions(target: any,
                                    propertyName: string,
                                    options: IPartialDefineAttributeColumnOptions): void {

  const attributes = getAttributes(target);

  if (!attributes || !attributes[propertyName]) {
    throw new Error(`@Column annotation is missing for "${propertyName}" of class "${target.constructor.name}"` +
      ` or annotation order is wrong.`);
  }

  attributes[propertyName] = deepAssign(attributes[propertyName], options);

  setAttributes(target, attributes);
}

/**
 * Returns sequelize define options from class prototype
 * by restoring this information from reflect metadata
 */
export function getOptions(target: any): DefineOptions<any>|undefined {

  const options = Reflect.getMetadata(OPTIONS_KEY, target);

  if (options) {
    return Object.assign({}, options);
  }
}

/**
 * Sets seuqlize define options to class prototype
 */
export function setOptions(target: any, options: DefineOptions<any>): void {

  Reflect.defineMetadata(OPTIONS_KEY, Object.assign({}, DEFAULT_OPTIONS, options), target);
}

/**
 * Adds options be assigning new options to old one
 */
export function addOptions(target: any, options: DefineOptions<any>): void {

  let _options = getOptions(target);

  if (!_options) {
    _options = {};
  }

  setOptions(target, Object.assign(_options, options));
}

/**
 * Maps design types to sequelize data types;
 * @throws if design type cannot be automatically mapped to
 * a sequelize data type
 */
export function getSequelizeTypeByDesignType(target: any, propertyName: string): DataTypeAbstract {

  const type = Reflect.getMetadata('design:type', target, propertyName);
  const dataType = inferDataType(type);

  if (dataType) {

    return dataType;
  }

  throw new Error(`Specified type of property '${propertyName}'
            cannot be automatically resolved to a sequelize data type. Please
            define the data type manually`);
}

/**
 * Determines models from value
 */
export function getModels(arg: Array<typeof Model|string>): Array<typeof Model> {

  if (arg && typeof arg[0] === 'string') {

    return arg.reduce((models: any[], dir) => {

      const _models = fs
        .readdirSync(dir as string)
        .filter(file => {
          // TODO extension is not necessarily only the lasst three characters
          const extension = file.slice(-3);
          return extension === '.js' || (extension === '.ts' && file.slice(-5) !== '.d.ts');
        })
        .map(file => path.parse(file).name)
        .filter(uniqueFilter)
        .map(fileName => {
          const fullPath = path.join(dir, fileName);
          const module = require(fullPath);

          if (!module[fileName] && !module.default) {
            throw new Error(`No default export defined for file "${fileName}" or export does not satisfy filename.`);
          }
          return module[fileName] || module.default;
        });

      models.push(..._models);

      return models;
    }, [])
      ;
  }

  return arg as Array<typeof Model>;
}

{'fraction_non_alphanumeric': 0.12015888778550149, 'fraction_numerical': 0.0006319400559718335, 'mean_word_length': 3.5852649006622515, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7449646', 'n_tokens_mistral': 3048, 'n_tokens_neox': 2964, 'n_words': 918}