drizzle-orm
drizzle-orm copied to clipboard
[MYSQL] Full text search (match against)
Added full text search (select <> from <> where match(<cols>) against (<query>)) (as specified here).
Changes include:
- added
inNaturalLanguageexpression - added
.againstcall - added
matchfor use withwhere - added
fulltextindexes (types only) - added test cases
I only implemented the fulltext index types for indexes but wasn't sure which direction to go for anything further. Also not super familiar with the codebase so feedback is welcome.
I've looked through the MySQL docs, and if I understood correctly, match and against are parts of a single expression: MATCH (col1,col2,...) AGAINST (expr [search_modifier]). So I feel like it should all be implemented as an operator function (maybe also using a builder syntax), something like this:
.where(
match(articles.title, articles.body)
.against('database')
.inNaturalSelectionMode()
)
Sorry for the delay on this, hoping to get to this by this weekend. Appreciate the feedback, definitely makes sense!
@corbanvilla does your implementation supports adding multiple columns as fulltext index (like in the below example)?
fulltextIndex('title_content_idx').on([Post.title, Post.content])
CREATE FULLTEXT INDEX `title_content_idx` ON `Post` (`title`, `content`);
Hi,
@corbanvilla it seems that you have not taken into account of @dankochetov about match and against. What is the status of this PR ?
Thanks !
I had to modify drizzle-kit for it to create my full text index, here is the patch
index 4508891..0e97fd2 100755
--- a/node_modules/drizzle-kit/index.js
+++ b/node_modules/drizzle-kit/index.js
@@ -6286,6 +6286,7 @@ var init_mysqlSchema = __esm({
name: stringType(),
columns: stringType().array(),
isUnique: booleanType(),
+ isFulltext: booleanType().optional(),
using: enumType(["btree", "hash"]).optional(),
algorithm: enumType(["default", "inplace", "copy"]).optional(),
lock: enumType(["default", "none", "shared", "exclusive"]).optional()
@@ -6394,14 +6395,16 @@ var init_mysqlSchema = __esm({
squashIdx: (idx) => {
var _a, _b, _c;
index.parse(idx);
- return `${idx.name};${idx.columns.join(",")};${idx.isUnique};${(_a = idx.using) != null ? _a : ""};${(_b = idx.algorithm) != null ? _b : ""};${(_c = idx.lock) != null ? _c : ""}`;
+
+ return `${idx.name};${idx.columns.join(",")};${idx.isUnique};${idx.isFulltext};${(_a = idx.using) != null ? _a : ""};${(_b = idx.algorithm) != null ? _b : ""};${(_c = idx.lock) != null ? _c : ""}`;
},
unsquashIdx: (input) => {
- const [name, columnsString, isUnique, using, algorithm, lock] = input.split(";");
+ const [name, columnsString, isUnique, isFulltext, using, algorithm, lock] = input.split(";");
const destructed = {
name,
columns: columnsString.split(","),
isUnique: isUnique === "true",
+ isFulltext: isFulltext === "true",
using: using ? using : void 0,
algorithm: algorithm ? algorithm : void 0,
lock: lock ? lock : void 0
@@ -21419,6 +21422,7 @@ var init_mysqlSerializer = __esm({
name,
columns: indexColumns,
isUnique: (_a = value.config.unique) != null ? _a : false,
+ isFulltext: (_a = value.config.fulltext) === true ? _a : undefined,
using: value.config.using,
algorithm: value.config.algorythm,
lock: value.config.lock
@@ -21615,6 +21619,7 @@ var init_mysqlSerializer = __esm({
const constraintName = idxRow["INDEX_NAME"];
const columnName = idxRow["COLUMN_NAME"];
const isUnique = idxRow["NON_UNIQUE"] === 0;
+ const isFulltext = idxRow["INDEX_TYPE"] === "FULLTEXT" ? true : undefined;
const tableInResult = result[tableName];
if (typeof tableInResult === "undefined")
continue;
@@ -21630,7 +21635,8 @@ var init_mysqlSerializer = __esm({
tableInResult.indexes[constraintName] = {
name: constraintName,
columns: [columnName],
- isUnique
+ isUnique,
+ isFulltext
};
}
}
@@ -24905,7 +24911,6 @@ ${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newCo
}
convert(statement) {
const { tableName, columnName } = statement;
- console.log(statement);
const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${statement.tableName}"` : `"${statement.tableName}"`;
return `ALTER TABLE ${tableNameWithSchema} ADD PRIMARY KEY ("${columnName}");`;
}
@@ -25140,10 +25145,10 @@ ${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newCo
return statement.type === "create_index" && dialect6 === "mysql";
}
convert(statement) {
- const { name, columns, isUnique } = MySqlSquasher.unsquashIdx(
+ const { name, columns, isUnique, isFulltext } = MySqlSquasher.unsquashIdx(
statement.data
);
- const indexPart = isUnique ? "UNIQUE INDEX" : "INDEX";
+ const indexPart = isFulltext ? "FULLTEXT INDEX": isUnique ? "UNIQUE INDEX" : "INDEX";
const value = columns.map((it) => `\`${it}\``).join(",");
return `CREATE ${indexPart} \`${name}\` ON \`${statement.tableName}\` (${value});`;
}
Any update on this feature? @corbanvilla
This is a very interesting feature that would benefit an app I'm working on. Is there any update on this? @corbanvilla
Closing in favor of #1030