diff --git a/src/flux/attributes/attribute-boolean.es6 b/src/flux/attributes/attribute-boolean.es6 index bb37af8b0..ba94f9d9b 100644 --- a/src/flux/attributes/attribute-boolean.es6 +++ b/src/flux/attributes/attribute-boolean.es6 @@ -15,6 +15,9 @@ export default class AttributeBoolean extends Attribute { fromJSON(val) { return ((val === 'true') || (val === true)) || false; } + fromColumn(val) { + return (val === 1) || false; + } columnSQL() { const defaultValue = this.defaultValue ? 1 : 0; return `${this.jsonKey} INTEGER DEFAULT ${defaultValue}`; diff --git a/src/flux/attributes/attribute.es6 b/src/flux/attributes/attribute.es6 index 0b6762baf..467064f75 100644 --- a/src/flux/attributes/attribute.es6 +++ b/src/flux/attributes/attribute.es6 @@ -10,11 +10,15 @@ The Attribute class also exposes convenience methods for generating {Matcher} ob Section: Database */ export default class Attribute { - constructor({modelKey, queryable, jsonKey, defaultValue}) { + constructor({modelKey, queryable, jsonKey, defaultValue, loadFromColumn}) { this.modelKey = modelKey; this.jsonKey = jsonKey || modelKey; this.queryable = queryable; this.defaultValue = defaultValue; + if (loadFromColumn && !queryable) { + throw new Error('loadFromColumn requires queryable'); + } + this.loadFromColumn = loadFromColumn; } _assertPresentAndQueryable(fnName, val) { @@ -77,4 +81,12 @@ export default class Attribute { fromJSON(val) { return val || null; } + + fromColumn(val) { + return this.fromJSON(val); + } + + needsColumn() { + return this.queryable && this.columnSQL && this.jsonKey !== 'id' + } } diff --git a/src/flux/models/query.es6 b/src/flux/models/query.es6 index 2450d7723..5e3d6c590 100644 --- a/src/flux/models/query.es6 +++ b/src/flux/models/query.es6 @@ -292,6 +292,13 @@ export default class ModelQuery { return result.map((row) => { const json = JSON.parse(row.data, Utils.registeredObjectReviver) const object = (new this._klass()).fromJSON(json); + for (const attrName of Object.keys(this._klass.attributes)) { + const attr = this._klass.attributes[attrName]; + if (!attr.needsColumn() || !attr.loadFromColumn) { + continue; + } + object[attr.modelKey] = attr.fromColumn(row[attr.jsonKey]); + } for (const attr of this._includeJoinedData) { let value = row[attr.jsonKey]; if (value === AttributeJoinedData.NullPlaceholder) { @@ -331,6 +338,13 @@ export default class ModelQuery { result = `\`${this._klass.name}\`.\`id\``; } else { result = `\`${this._klass.name}\`.\`data\``; + for (const attrName of Object.keys(this._klass.attributes)) { + const attr = this._klass.attributes[attrName]; + if (!attr.needsColumn() || !attr.loadFromColumn) { + continue; + } + result += `, ${attr.jsonKey} `; + } this._includeJoinedData.forEach((attr) => { result += `, ${attr.selectSQL(this._klass)} `; }) diff --git a/src/flux/models/thread.es6 b/src/flux/models/thread.es6 index 4a6c5146c..ab0dbaa01 100644 --- a/src/flux/models/thread.es6 +++ b/src/flux/models/thread.es6 @@ -111,6 +111,7 @@ class Thread extends ModelWithMetadata { modelKey: 'isSearchIndexed', jsonKey: 'is_search_indexed', defaultValue: false, + loadFromColumn: true, }), }) diff --git a/src/flux/stores/database-setup-query-builder.es6 b/src/flux/stores/database-setup-query-builder.es6 index 74622cafc..1bd0ad17a 100644 --- a/src/flux/stores/database-setup-query-builder.es6 +++ b/src/flux/stores/database-setup-query-builder.es6 @@ -42,9 +42,7 @@ export default class DatabaseSetupQueryBuilder { // Identify attributes of this class that can be matched against. These // attributes need their own columns in the table - const columnAttributes = attributes.filter(attr => - attr.queryable && attr.columnSQL && attr.jsonKey !== 'id' - ); + const columnAttributes = attributes.filter(attr => attr.needsColumn()) const columns = ['id TEXT PRIMARY KEY', 'data BLOB'] columnAttributes.forEach(attr => columns.push(attr.columnSQL()));