public function save()
    {
        static::checkReadOnly();

        $is_fresh = $this->isFresh();

        $this->updateStampColumns();

        if (($is_fresh && !$this->onFirstSave())
            || !$this->onSave()
            || empty($this->changes)
        ) {
            return;
        }

        $data = $this->changes;
        $data = static::validate($data, $is_fresh);

        $database = self::getDatabase();
        $stmt = ($is_fresh)
            ? $database->insert(static::TABLE, $data)
            : $database->update(static::TABLE, $data, $this->getPrimaryKey());

        $error_code = $stmt->errorCode();
        if ($error_code == '00000') {
            /*
             * It is prefered to load back because the Database may apply
             * default values or alter some columns. Also, it forces updating
             * foreign models.
             *
             * - If it was a fresh model with AUTO_INCREMENT, get the new value
             * - Extract the PRIMARY_KEY
             * - Load from Database
             */
            $data = $this->getData();
            if ($is_fresh) {
                $column = static::AUTO_INCREMENT;
                if ($column !== null) {
                    $data[$column] = $database->id();
                }
            }
            $where = Utils::arrayWhitelist($data, static::PRIMARY_KEY);
            return $this->load($where);
        }
        return $error_code;
    }