<commit_before>//----------------------------------------------------------------------------------------------------------------------
// Implements a model based API for TrivialDB.
//
// @module models.js
//----------------------------------------------------------------------------------------------------------------------

var util = require('util');

var _ = require('lodash');
var oftype = require('oftype');
var Promise = require('bluebird');

var errors = require('./errors');

//----------------------------------------------------------------------------------------------------------------------

function Model(modelDef)
{
    this.$$relations = {};
    this.$$updates = {};
    this.$$values = modelDef || {};

    // Dirty can be read by external things, but we prefix it with '$' to prevent property collision.
    this.$dirty = true;

    // Ensure that our relations are built.
    buildRelations(this.constructor);
} // end Model

function buildSchema(model)
{
    var proto = model.prototype;
    var pk = proto.$$db.options.pk ? proto.$$db.options.pk : 'id';

    // Setup the id property
    Object.defineProperty(proto, 'id', {
        get: function() { return this.$$values[pk]; },
        set: function(val)
        {
            // We only allow setting in the event that id is undefined.
            if(this.$$values.id === undefined)
            {
                this.$dirty = true;
                this.$$values[pk] = val;
            } // end if
        }
    });

    // Setup the schema properties
    _.forIn(proto.$$schema, function(typeDef, key)
    {
        if(key != '$relations')
        {
            attachKeyToProto(proto, typeDef, key);
        } // end if
    });
    
    buildRelations(model);
} // end buildSchema

function attachKeyToProto(proto, typeDef, key)
{
    if(_.isFunction(typeDef))
    {
        typeDef = {type: typeDef};
    } // end if

    if(!_.isPlainObject(typeDef))
    {
        var err = new Error(
            "Invalid type definition! Should be a function, an object with a `type` function, or a subschema object."
        );
        err.value = typeDef;
        throw err;
    } // end if

    if(_.isFunction(typeDef.type))
    {
        Object.defineProperty(proto, key, {
            get: function()
            {
                // Check to see if we have a value in $$updates, if not, then we check $$values. Finally, if val is
                // still undefined, we grab the default value.
                var val = _.has(this.$$updates, key) ? this.$$updates[key] : this.$$values[key];
                val = val === undefined ? typeDef.default : val;

                switch(typeDef.type)
                {
                    case Date:
                        return _.isDate(val) ? _.clone(val) : new Date(val);
                    default:
                        return _.clone(val);
                } // end switch
            },
            set: function(newVal)
            {
                this.$dirty = true;
                switch(typeDef.type)
                {
                    case Date:<commit_msg>fixed another issue with nested models.<commit_after>//----------------------------------------------------------------------------------------------------------------------
// Implements a model based API for TrivialDB.
//
// @module models.js
//----------------------------------------------------------------------------------------------------------------------

var util = require('util');

var _ = require('lodash');
var oftype = require('oftype');
var Promise = require('bluebird');

var errors = require('./errors');

//----------------------------------------------------------------------------------------------------------------------

function Model(modelDef)
{
    this.$$relations = {};
    this.$$updates = {};
    this.$$values = modelDef || {};

    // Dirty can be read by external things, but we prefix it with '$' to prevent property collision.
    this.$dirty = true;

    // Ensure that our relations are built.
    buildRelations(this.constructor);
} // end Model

function buildSchema(model)
{
    var proto = model.prototype;
    var pk = proto.$$db.options.pk ? proto.$$db.options.pk : 'id';

    // Setup the id property
    Object.defineProperty(proto, 'id', {
        get: function() { return this.$$values[pk]; },
        set: function(val)
        {
            // We only allow setting in the event that id is undefined.
            if(this.$$values.id === undefined)
            {
                this.$dirty = true;
                this.$$values[pk] = val;
            } // end if
        }
    });

    // Setup the schema properties
    _.forIn(proto.$$schema, function(typeDef, key)
    {
        if(key != '$relations')
        {
            attachKeyToProto(proto, typeDef, key);
        } // end if
    });
    
    buildRelations(model);
} // end buildSchema

function attachKeyToProto(proto, typeDef, key)
{
    if(_.isFunction(typeDef))
    {
        typeDef = {type: typeDef};
    } // end if

    if(!_.isPlainObject(typeDef))
    {
        var err = new Error(
            "Invalid type definition! Should be a function, an object with a `type` function, or a subschema object."
        );
        err.value = typeDef;
        throw err;
    } // end if

    if(_.isFunction(typeDef.type))
    {
        Object.defineProperty(proto, key, {
            get: function()
            {
                // Check to see if we have a value in $$updates, if not, then we check $$values. Finally, if val is
                // still undefined, we grab the default value.
                var val = _.has(this.$$updates, key) ? this.$$updates[key] : this.$$values ? this.$$values[key] : undefined;
                val = val === undefined ? typeDef.default : val;

                switch(typeDef.type)
                {
                    case Date:
                        return _.isDate(val) ? _.clone(val) : new Date(val);
                    default:
                        return _.clone(val);
                } // end switch
            },
            set: function(newVal)
            {
                this.$dirty = true;
                switch(typeDef.type)
                {
                    case Date:
{'fraction_non_alphanumeric': 0.22784, 'fraction_numerical': 0.0, 'mean_word_length': 1.229315263908702, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '1012119', 'n_tokens_mistral': 1590, 'n_tokens_neox': 1508, 'n_words': 438}