Skip to content

Commit

Permalink
feat: Add support for FULLTEXT indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
nwoltman committed May 9, 2019
1 parent 8cab7ce commit 673fad7
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 3 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1162,11 +1162,13 @@ Keys can be defined with the `keys` property, which is an array of [`KeyTypes`](
accountID: pool.ColTypes.int().unsigned().notNull(),
email: pool.ColTypes.varchar(255).notNull(),
location: pool.ColTypes.point().notNull(),
description: pool.ColTypes.text(),
},
keys: [
pool.KeyTypes.index('accountID'),
pool.KeyTypes.uniqueIndex('email'),
pool.KeyTypes.spatialIndex('location'),
pool.KeyTypes.fulltextIndex('description'),
pool.KeyTypes.foreignKey('accountID').references('account', 'id'),
]
}
Expand Down Expand Up @@ -1305,6 +1307,7 @@ Methods:

+ `charset(value)` - Sets the column's character set
+ `collate(value)` - Sets the column's collation
+ `fulltextIndex()` - Creates a [fulltext index](https://dev.mysql.com/doc/en/innodb-fulltext-index.html) for the column (excluding `enum` and `set` columns)

Compatible types:

Expand Down Expand Up @@ -1375,7 +1378,7 @@ Normally if the `DEFAULT` is unspecified, MySQL uses `CURRENT_TIMESTAMP` as the

Methods:

+ `spatialIndex()` - Creates a spatial index for the column
+ `spatialIndex()` - Creates a [spatial index](https://dev.mysql.com/doc/en/create-index.html#create-index-spatial) for the column

Compatible types:

Expand All @@ -1395,6 +1398,7 @@ Compatible types:
+ `index(columnName [, ...otherColumns])` - Creates a regular [index](https://dev.mysql.com/doc/en/create-index.html)
+ `uniqueIndex(columnName [, ...otherColumns])` - Creates a [unique index](https://dev.mysql.com/doc/en/create-index.html#create-index-unique)
+ `spatialIndex(columnName)` - Creates a [spatial index](https://dev.mysql.com/doc/en/create-index.html#create-index-spatial)
+ `fulltextIndex(columnName)` - Creates a [fulltext index](https://dev.mysql.com/doc/en/innodb-fulltext-index.html)
+ `foreignKey(columnName [, ...otherColumns])` - Creates a [foreign key constraint](https://dev.mysql.com/doc/en/create-table-foreign-keys.html)

**Example:**
Expand All @@ -1404,6 +1408,7 @@ Compatible types:
pool.KeyTypes.index('accountID'),
pool.KeyTypes.uniqueIndex('email'),
pool.KeyTypes.spatialIndex('location'),
pool.KeyTypes.fulltextIndex('description'),
pool.KeyTypes.foreignKey('accountID').references('account', 'id'),

// Multi-column keys
Expand All @@ -1421,6 +1426,7 @@ All key types have a `name` method that can be used to customize the key’s nam
pool.KeyTypes.index('accountID').name('account_key'),
pool.KeyTypes.uniqueIndex('email').name('email_key'),
pool.KeyTypes.spatialIndex('location').name('location_key'),
pool.KeyTypes.fulltextIndex('description').name('description_key'),
pool.KeyTypes.foreignKey('accountID').references('account', 'id').name('account_foreign_key'),
]
}
Expand Down
8 changes: 7 additions & 1 deletion jsdoc2md/README.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,13 @@ Keys can be defined with the `keys` property, which is an array of [`KeyTypes`](
accountID: pool.ColTypes.int().unsigned().notNull(),
email: pool.ColTypes.varchar(255).notNull(),
location: pool.ColTypes.point().notNull(),
description: pool.ColTypes.text(),
},
keys: [
pool.KeyTypes.index('accountID'),
pool.KeyTypes.uniqueIndex('email'),
pool.KeyTypes.spatialIndex('location'),
pool.KeyTypes.fulltextIndex('description'),
pool.KeyTypes.foreignKey('accountID').references('account', 'id'),
]
}
Expand Down Expand Up @@ -346,6 +348,7 @@ Methods:

+ `charset(value)` - Sets the column's character set
+ `collate(value)` - Sets the column's collation
+ `fulltextIndex()` - Creates a [fulltext index](https://dev.mysql.com/doc/en/innodb-fulltext-index.html) for the column (excluding `enum` and `set` columns)

Compatible types:

Expand Down Expand Up @@ -416,7 +419,7 @@ Normally if the `DEFAULT` is unspecified, MySQL uses `CURRENT_TIMESTAMP` as the

Methods:

+ `spatialIndex()` - Creates a spatial index for the column
+ `spatialIndex()` - Creates a [spatial index](https://dev.mysql.com/doc/en/create-index.html#create-index-spatial) for the column

Compatible types:

Expand All @@ -436,6 +439,7 @@ Compatible types:
+ `index(columnName [, ...otherColumns])` - Creates a regular [index](https://dev.mysql.com/doc/en/create-index.html)
+ `uniqueIndex(columnName [, ...otherColumns])` - Creates a [unique index](https://dev.mysql.com/doc/en/create-index.html#create-index-unique)
+ `spatialIndex(columnName)` - Creates a [spatial index](https://dev.mysql.com/doc/en/create-index.html#create-index-spatial)
+ `fulltextIndex(columnName)` - Creates a [fulltext index](https://dev.mysql.com/doc/en/innodb-fulltext-index.html)
+ `foreignKey(columnName [, ...otherColumns])` - Creates a [foreign key constraint](https://dev.mysql.com/doc/en/create-table-foreign-keys.html)

**Example:**
Expand All @@ -445,6 +449,7 @@ Compatible types:
pool.KeyTypes.index('accountID'),
pool.KeyTypes.uniqueIndex('email'),
pool.KeyTypes.spatialIndex('location'),
pool.KeyTypes.fulltextIndex('description'),
pool.KeyTypes.foreignKey('accountID').references('account', 'id'),

// Multi-column keys
Expand All @@ -462,6 +467,7 @@ All key types have a `name` method that can be used to customize the key’s nam
pool.KeyTypes.index('accountID').name('account_key'),
pool.KeyTypes.uniqueIndex('email').name('email_key'),
pool.KeyTypes.spatialIndex('location').name('location_key'),
pool.KeyTypes.fulltextIndex('description').name('description_key'),
pool.KeyTypes.foreignKey('accountID').references('account', 'id').name('account_foreign_key'),
]
}
Expand Down
6 changes: 6 additions & 0 deletions lib/ColumnDefinitions/TextColumnDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const ColumnDefinition = require('./ColumnDefinition');
class TextColumnDefinition extends ColumnDefinition {
constructor(type, m) {
super(type, m);
this.$fulltextIndex = false;
this._charset = null;
this._collate = null;
}
Expand All @@ -19,6 +20,11 @@ class TextColumnDefinition extends ColumnDefinition {
return this;
}

fulltextIndex() {
this.$fulltextIndex = true;
return this;
}

$equals(columnDefinition, columnTableSchema) {
if (!super.$equals(columnDefinition)) {
return false;
Expand Down
4 changes: 4 additions & 0 deletions lib/KeyDefinitions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const KeyDefinitions = {
throwIfNoColumns(columns);
return new IndexKeyDefinition('SPATIAL INDEX', 'sptl', columns);
},
fulltextIndex(...columns) {
throwIfNoColumns(columns);
return new IndexKeyDefinition('FULLTEXT INDEX', 'fltxt', columns);
},
foreignKey(...columns) {
throwIfNoColumns(columns);
return new ForeignKeyDefinition(columns);
Expand Down
4 changes: 4 additions & 0 deletions lib/TableDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ function createInternalSchema(schema, tableName) {
const key = KeyDefinitions.spatialIndex(columnName);
indexKeys[key.$name] = key;
}
if (column.$fulltextIndex) {
const key = KeyDefinitions.fulltextIndex(columnName);
indexKeys[key.$name] = key;
}
}

if (schema.primaryKey) {
Expand Down
5 changes: 5 additions & 0 deletions lib/sqlToSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ function generatePrimaryKeySchema(keySQL) {
const rgxUniqueKey = /^\s*UNIQUE KEY `(\w+)` \((.*?)\)/;
const rgxIndexKey = /^\s*KEY `(\w+)` \((.*?)\)/;
const rgxSpatialKey = /^\s*SPATIAL KEY `(\w+)` \((.*?)\)/;
const rgxFulltextKey = /^\s*FULLTEXT KEY `(\w+)` \((.*?)\)/;
const rgxForeignKey =
/\s*CONSTRAINT `(\w+)` FOREIGN KEY \(`(.*?)`\) REFERENCES `(\w+)` \(`(.*?)`\)(?: ON DELETE (RESTRICT|CASCADE|SET NULL|NO ACTION))?(?: ON UPDATE (RESTRICT|CASCADE|SET NULL|NO ACTION))?/;

Expand All @@ -181,6 +182,10 @@ function generateKeySchema(keySQL) {
return KeyDefinitions.spatialIndex(...columnsSQLToSchema(keyMatch[2])).name(keyMatch[1]);
}

if ((keyMatch = rgxFulltextKey.exec(keySQL)) !== null) {
return KeyDefinitions.fulltextIndex(...columnsSQLToSchema(keyMatch[2])).name(keyMatch[1]);
}

if ((keyMatch = rgxForeignKey.exec(keySQL)) !== null) {
const foreignKey = KeyDefinitions
.foreignKey(...columnsSQLToSchema(keyMatch[2]))
Expand Down
78 changes: 77 additions & 1 deletion test/integration/MySQLPlus.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('MySQLPlus', function() {
jdoc: ColTypes.json(),
location: ColTypes.point().notNull().spatialIndex(),
line: ColTypes.linestring(),
description: ColTypes.text().fulltextIndex(),
},
keys: [
KeyTypes.uniqueIndex('name', 'letter'),
Expand All @@ -52,12 +53,14 @@ describe('MySQLPlus', function() {
' `jdoc` json DEFAULT NULL,\n' +
' `location` point NOT NULL,\n' +
' `line` linestring DEFAULT NULL,\n' +
' `description` text,\n' +
' PRIMARY KEY (`id`),\n' +
' UNIQUE KEY `uniq_email` (`email`),\n' +
' UNIQUE KEY `uniq_name_letter` (`name`,`letter`),\n' +
' UNIQUE KEY `uniq_created` (`created`),\n' +
' KEY `idx_letter` (`letter`),\n' +
' SPATIAL KEY `sptl_location` (`location`)\n' +
' SPATIAL KEY `sptl_location` (`location`),\n' +
' FULLTEXT KEY `fltxt_description` (`description`)\n' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8';

const autoIncTableName = 'auto_inc_table';
Expand Down Expand Up @@ -345,6 +348,47 @@ describe('MySQLPlus', function() {
' SPATIAL KEY `sptl_c` (`c`)\n' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8';

const fulltextIndexesTableName = 'fulltext_table';
const fulltextIndexesTableSchema = {
columns: {
a: ColTypes.char(32).notNull(),
b: ColTypes.varchar(255).notNull(),
c: ColTypes.text().notNull(),
},
keys: [
KeyTypes.fulltextIndex('a'),
KeyTypes.fulltextIndex('b'),
],
};
const fulltextIndexesTableExpectedSQL =
'CREATE TABLE `fulltext_table` (\n' +
' `a` char(32) NOT NULL,\n' +
' `b` varchar(255) NOT NULL,\n' +
' `c` text NOT NULL,\n' +
' FULLTEXT KEY `fltxt_a` (`a`),\n' +
' FULLTEXT KEY `fltxt_b` (`b`)\n' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8';

const fulltextIndexesTableMigragedSchema = {
columns: {
a: ColTypes.char(32).notNull(),
b: ColTypes.varchar(255).notNull(),
c: ColTypes.text().notNull(),
},
keys: [
KeyTypes.fulltextIndex('a'),
KeyTypes.fulltextIndex('c'),
],
};
const fulltextIndexesTableMigratedExpectedSQL =
'CREATE TABLE `fulltext_table` (\n' +
' `a` char(32) NOT NULL,\n' +
' `b` varchar(255) NOT NULL,\n' +
' `c` text NOT NULL,\n' +
' FULLTEXT KEY `fltxt_a` (`a`),\n' +
' FULLTEXT KEY `fltxt_c` (`c`)\n' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8';

const foreignKeysTableName = 'fk_table';
const foreignKeysTableSchema = {
columns: {
Expand Down Expand Up @@ -567,6 +611,7 @@ describe('MySQLPlus', function() {
pool.defineTable(uniqueKeysTableName, uniqueKeysTableSchema);
pool.defineTable(indexesTableName, indexesTableSchema);
pool.defineTable(spatialIndexesTableName, spatialIndexesTableSchema);
pool.defineTable(fulltextIndexesTableName, fulltextIndexesTableSchema);
pool.defineTable(foreignKeysTableName, foreignKeysTableSchema);
pool.defineTable(optionsTableName, optionsTableSchema);
pool.defineTable(textTableName, textTableSchema);
Expand Down Expand Up @@ -638,6 +683,13 @@ describe('MySQLPlus', function() {
cbSpatial();
});

const cbFulltext = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${fulltextIndexesTableName}\``, (err, result) => {
if (err) throw err;
result[0]['Create Table'].should.equal(fulltextIndexesTableExpectedSQL);
cbFulltext();
});

const cb8 = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${foreignKeysTableName}\``, (err, result) => {
if (err) throw err;
Expand Down Expand Up @@ -691,6 +743,7 @@ describe('MySQLPlus', function() {
pool.defineTable(uniqueKeysTableName, uniqueKeysTableSchema);
pool.defineTable(indexesTableName, indexesTableSchema);
pool.defineTable(spatialIndexesTableName, spatialIndexesTableSchema);
pool.defineTable(fulltextIndexesTableName, fulltextIndexesTableSchema);
pool.defineTable(foreignKeysTableName, foreignKeysTableSchema);
pool.defineTable(optionsTableName, optionsTableSchema);
pool.defineTable(textTableName, textTableSchema);
Expand Down Expand Up @@ -767,6 +820,13 @@ describe('MySQLPlus', function() {
cbSpatial();
});

const cbFulltext = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${fulltextIndexesTableName}\``, (err, result) => {
if (err) throw err;
result[0]['Create Table'].should.equal(fulltextIndexesTableExpectedSQL);
cbFulltext();
});

const cb8 = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${foreignKeysTableName}\``, (err, result) => {
if (err) throw err;
Expand Down Expand Up @@ -820,6 +880,7 @@ describe('MySQLPlus', function() {
pool.defineTable(uniqueKeysTableName, uniqueKeysTableSchema);
pool.defineTable(indexesTableName, indexesTableSchema);
pool.defineTable(spatialIndexesTableName, spatialIndexesTableSchema);
pool.defineTable(fulltextIndexesTableName, fulltextIndexesTableSchema);
pool.defineTable(foreignKeysTableName, foreignKeysTableSchema);
pool.defineTable(optionsTableName, optionsTableSchema);
pool.defineTable(textTableName, textTableSchema);
Expand Down Expand Up @@ -891,6 +952,13 @@ describe('MySQLPlus', function() {
cbSpatial();
});

const cbFulltext = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${fulltextIndexesTableName}\``, (err, result) => {
if (err) throw err;
result[0]['Create Table'].should.equal(fulltextIndexesTableExpectedSQL);
cbFulltext();
});

const cb8 = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${foreignKeysTableName}\``, (err, result) => {
if (err) throw err;
Expand Down Expand Up @@ -943,6 +1011,7 @@ describe('MySQLPlus', function() {
pool.defineTable(uniqueKeysTableName, uniqueKeysTableMigragedSchema);
pool.defineTable(indexesTableName, indexesTableMigragedSchema);
pool.defineTable(spatialIndexesTableName, spatialIndexesTableMigragedSchema);
pool.defineTable(fulltextIndexesTableName, fulltextIndexesTableMigragedSchema);
pool.defineTable(foreignKeysTableName, foreignKeysTableMigratedSchema);
pool.defineTable(optionsTableName, optionsTableMigratedSchema);

Expand Down Expand Up @@ -1020,6 +1089,13 @@ describe('MySQLPlus', function() {
cbSpatial();
});

const cbFulltext = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${fulltextIndexesTableName}\``, (err, result) => {
if (err) throw err;
result[0]['Create Table'].should.equal(fulltextIndexesTableMigratedExpectedSQL);
cbFulltext();
});

const cb8 = cbManager.registerCallback();
pool.query(`SHOW CREATE TABLE \`${foreignKeysTableName}\``, (err, result) => {
if (err) throw err;
Expand Down
26 changes: 26 additions & 0 deletions test/unit/ColumnDefinitions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,12 @@ describe('ColumnDefinitions', () => {

ColumnDefinitions.point().notNull().index().spatialIndex()
.$toSQL().should.equal('point NOT NULL');

ColumnDefinitions.text().fulltextIndex()
.$toSQL().should.equal('text');

ColumnDefinitions.longtext().notNull().index().fulltextIndex()
.$toSQL().should.equal('longtext NOT NULL');
});

it('should allow the columns to be defined as primary keys, but not change the SQL, except for forcing the column to be NOT NULL', () => {
Expand Down Expand Up @@ -500,6 +506,26 @@ describe('ColumnDefinitions', () => {
.$toSQL().should.equal('char CHARACTER SET utf8 COLLATE utf8_general_ci');
});

it('should be able to create fulltext indexes', () => {
ColumnDefinitions.char(32).fulltextIndex()
.$toSQL().should.equal('char(32)');

ColumnDefinitions.varchar(255).fulltextIndex()
.$toSQL().should.equal('varchar(255)');

ColumnDefinitions.text().fulltextIndex()
.$toSQL().should.equal('text');

ColumnDefinitions.tinytext().fulltextIndex()
.$toSQL().should.equal('tinytext');

ColumnDefinitions.mediumtext().fulltextIndex()
.$toSQL().should.equal('mediumtext');

ColumnDefinitions.longtext().fulltextIndex()
.$toSQL().should.equal('longtext');
});

});


Expand Down
Loading

0 comments on commit 673fad7

Please sign in to comment.