diff --git a/packages/babel-plugin/README.md b/packages/babel-plugin/README.md index 6f5255cf7d..87cb050fda 100644 --- a/packages/babel-plugin/README.md +++ b/packages/babel-plugin/README.md @@ -206,10 +206,10 @@ Note that use of decorators requires using the `@babel/plugin-proposal-decorator This table shows the available decorators: -| Decorator | Parameters | Notes | -| --------- | ----------------------------- | ---------------------------------------------------------------------------------------------------- | -| `index` | none | Specifies that the decorated property should be indexed by Realm. | -| `mapTo` | `(realmPropertyName: string)` | Specifies that the decorated property should be stored as `realmPropertyName` in the Realm database. | +| Decorator | Parameters | Notes | +|-----------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `index` | none or `("full-text")` | Specifies that the decorated property should be indexed by Realm. Providing the string "full-text" specifies that the property should be indexed for full-text search by Realm. | +| `mapTo` | `(realmPropertyName: string)` | Specifies that the decorated property should be stored as `realmPropertyName` in the Realm database. | The example below shows both decorators in use: @@ -219,8 +219,11 @@ import { mapTo, index } from "@realm/babel-plugin"; export class Task extends Realm.Object { _id!: Realm.BSON.ObjectId; - // Add an index to the `description` property + // Add an index to the `assignee` property @index + assignee!: string; + // Specify that the `description` property should be indexed for full-text search + @index("full-text") description!: string; // Specify that the `isComplete` property should be stored as `complete` in the Realm database @mapTo("complete") diff --git a/packages/babel-plugin/src/index.test.ts b/packages/babel-plugin/src/index.test.ts index 686224b358..5a2abc65cb 100644 --- a/packages/babel-plugin/src/index.test.ts +++ b/packages/babel-plugin/src/index.test.ts @@ -390,6 +390,39 @@ describe("Babel plugin", () => { expect(transformCode).not.toContain("_applyDecoratedDescriptor"); }); + it('handles `@index("full-text")` decorators', () => { + const transformCode = transformProperty(`@index("full-text") name: Realm.Types.String;`); + const parsedSchema = extractSchema(transformCode); + + expect((parsedSchema?.properties.name as PropertySchema).indexed).toEqual("full-text"); + }) + + it('handles `@index("full-text")` decorators from the Realm import', () => { + const transformCode = transform({ + source: `import Realm, { Types, BSON, List, Set, Dictionary, Mixed } from "realm"; + export class Person extends Realm.Object { @Realm.index("full-text") name: Realm.Types.String; }`, + }); + const parsedSchema = extractSchema(transformCode); + + expect((parsedSchema?.properties.name as PropertySchema).indexed).toEqual("full-text"); + }); + + it('ignores `@index("full-text")` decorators not imported from `realm`', () => { + const transformCode = transform({ + source: `import Realm, { Types, BSON, List, Set, Dictionary, Mixed } from "realm"; + export class Person extends Realm.Object { @index("full-text") name: Realm.Types.String; }`, + }); + const parsedSchema = extractSchema(transformCode); + + expect((parsedSchema?.properties.name as PropertySchema).indexed).toBeUndefined(); + }); + + it('removes `@index("full-text")` decorators from the source', () => { + const transformCode = transformProperty(`@index("full-text") name: Realm.Types.String;`); + // This is what Babel outputs for transformed decorators + expect(transformCode).not.toContain("_applyDecoratedDescriptor"); + }); + it("handles `@mapTo` decorators", () => { const transformCode = transformProperty(`@mapTo("rename") name: Realm.Types.String;`); const parsedSchema = extractSchema(transformCode); diff --git a/packages/babel-plugin/src/plugin/index.ts b/packages/babel-plugin/src/plugin/index.ts index 17e60c83ea..0aa1105e54 100644 --- a/packages/babel-plugin/src/plugin/index.ts +++ b/packages/babel-plugin/src/plugin/index.ts @@ -290,6 +290,13 @@ function visitRealmClassProperty(path: NodePath) { } const index = Boolean(indexDecorator); + const indexDecoratorCall = findDecoratorCall(decoratorsPath, "index"); + const indexCall = + indexDecoratorCall + && types.isStringLiteral(indexDecoratorCall.callExpression.arguments[0]) + ? indexDecoratorCall.callExpression.arguments[0].value + : undefined; + const mapToDecorator = findDecoratorCall(decoratorsPath, "mapTo"); const mapTo = mapToDecorator && types.isStringLiteral(mapToDecorator.callExpression.arguments[0]) @@ -299,6 +306,7 @@ function visitRealmClassProperty(path: NodePath) { // Remove the decorators from the final source as they are only for schema annotation purposes. // Decorator implementations will throw to prevent usage outside of the plugin. if (indexDecorator) indexDecorator.remove(); + if (indexDecoratorCall) indexDecoratorCall.decoratorNode.remove(); if (mapToDecorator) mapToDecorator.decoratorNode.remove(); if (keyPath.isIdentifier()) { @@ -336,6 +344,10 @@ function visitRealmClassProperty(path: NodePath) { properties.push(types.objectProperty(types.identifier("indexed"), types.booleanLiteral(true))); } + if (indexCall) { + properties.push(types.objectProperty(types.identifier("indexed"), types.stringLiteral(indexCall))) + } + if (mapTo) { properties.push(types.objectProperty(types.identifier("mapTo"), types.stringLiteral(mapTo))); }