From 9173a5d74177410ccb75f0007829a285e47db171 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 21 May 2024 09:05:17 -0400 Subject: [PATCH 01/12] Update RQL data models & move all RQL tests/snippets to v12. Add typescript tests --- .../v12/__tests__/models/rql-data-models.ts | 57 +- .../__tests__/realm-query-language.test.js | 908 ++++++++++++++++-- 2 files changed, 889 insertions(+), 76 deletions(-) diff --git a/examples/node/v12/__tests__/models/rql-data-models.ts b/examples/node/v12/__tests__/models/rql-data-models.ts index 210aaddcdc..59c60d2344 100644 --- a/examples/node/v12/__tests__/models/rql-data-models.ts +++ b/examples/node/v12/__tests__/models/rql-data-models.ts @@ -1,5 +1,36 @@ import Realm, { BSON, ObjectSchema } from "realm"; +// Models for embedded objects & dot notation queries +export class Address extends Realm.Object
{ + name!: string; + street!: string; + zipcode!: number; + + static schema: ObjectSchema = { + name: "Address", + embedded: true, + properties: { + name: "string", + street: "string", + zipcode: "int", + }, + }; +} + +export class Office extends Realm.Object { + name!: string; + address!: Address; + + static schema: ObjectSchema = { + name: "Office", + properties: { + name: "string", + address: "Address", + }, + }; +} + +// :snippet-start: rql-data-models export class Item extends Realm.Object { _id!: BSON.ObjectId; name!: string; @@ -12,17 +43,11 @@ export class Item extends Realm.Object { name: "Item", properties: { _id: "objectId", - name: { type:"string", indexed: "full-text" }, + name: { type: "string", indexed: "full-text" }, isComplete: { type: "bool", default: false }, assignee: "string?", - priority: { - type: "int", - default: 0, - }, - progressMinutes: { - type: "int", - default: 0, - }, + priority: { type: "int", default: 0 }, + progressMinutes: { type: "int", default: 0 }, projects: { type: "linkingObjects", objectType: "Project", @@ -32,12 +57,13 @@ export class Item extends Realm.Object { primaryKey: "_id", }; } - export class Project extends Realm.Object { _id!: BSON.ObjectId; name!: string; - items!: Realm.List - quota?: number + items!: Realm.List; + quota?: number; + comments?: Realm.Dictionary; + projectLocation?: Office; static schema: ObjectSchema = { name: "Project", @@ -46,7 +72,10 @@ export class Project extends Realm.Object { name: "string", items: "Item[]", quota: "int?", + comments: "string?{}", + projectLocation: "Office?", }, primaryKey: "_id", - } -}; + }; +} +// :snippet-end: diff --git a/examples/node/v12/__tests__/realm-query-language.test.js b/examples/node/v12/__tests__/realm-query-language.test.js index 81a11913c9..4b0a0c2c9d 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.js +++ b/examples/node/v12/__tests__/realm-query-language.test.js @@ -1,22 +1,52 @@ +/* eslint-disable prettier/prettier */ import Realm, { BSON } from "realm"; -import { Item, Project } from "./models/rql-data-models.ts"; +import { Address, Item, Office, Project } from "./models/rql-data-models.ts"; +import { describe, expect } from "@jest/globals"; describe("Realm Query Language Reference", () => { let realm; + const config = { schema: [Project, Item, Address, Office] }; + beforeEach(async () => { - realm = await Realm.open({ - schema: [Project, Item], - deleteRealmIfMigrationNeeded: true, - }); + // Before each test, open the realm and create project & item objects: + // 2 branches w/ 2 addresses; 3 projects; and + // 6 items (one used in 2 projects, another in 0 projects) + realm = await Realm.open(config); - // populate test objects + const mainBranch = { + name: "Main Branch", + address: { + name: "Main Branch", + street: "123 Main St", + zipcode: 10019, + }, + }; + const austinBranch = { + name: "Austin Branch", + address: { + name: "Austin Branch", + street: "123 Main Ave", + zipcode: 10019, + }, + }; realm.write(() => { - realm.create("Project", { - _id: new Realm.BSON.ObjectId(), - name: "New Project", + realm.create(Item, { + // Unassigned incomplete item not in any project + _id: new BSON.ObjectId("631a073c833a34ade21db2b2"), + name: "Write tests", + isComplete: false, + assignee: null, + priority: 10, + progressMinutes: 0, + }); + + realm.create(Project, { + _id: new BSON.ObjectId(), + name: "Example Project with Items", items: [ { - _id: new Realm.BSON.ObjectId(), + // Alex incomplete item + _id: new BSON.ObjectId("631a072f75120729dc9223d9"), name: "Write tests", isComplete: false, assignee: "Alex", @@ -24,73 +54,76 @@ describe("Realm Query Language Reference", () => { progressMinutes: 125, }, { - _id: new Realm.BSON.ObjectId(), + // Ali incomplete item + _id: new BSON.ObjectId("631a0737c98f89f5b81cd24d"), name: "Run tests", isComplete: false, assignee: "Ali", priority: 9, progressMinutes: 10, }, - { - _id: new Realm.BSON.ObjectId(), - name: "Bluehawk Tests", - isComplete: false, - assignee: null, - priority: 10, - progressMinutes: 55, - }, ], + quota: 1, // doesn't meet quota + comments: { status: "Behind schedule", projectNumber: "70150" }, + projectLocation: mainBranch, }); - const proj1 = realm.create("Project", { - _id: new Realm.BSON.ObjectId(), - name: "Project with High Quota", - quota: 12, + const project = realm.create(Project, { + _id: new BSON.ObjectId(), + name: "Project that Meets Quota", items: [ { - _id: new Realm.BSON.ObjectId(), - name: "Create a ticket", + // Complete item used in 2 projects + _id: new BSON.ObjectId(), + name: "Approve project plan", isComplete: true, - assignee: "Nick", - priority: 2, - progressMinutes: 8, + assignee: "Dachary", + priority: 1, + progressMinutes: 0, }, { - _id: new Realm.BSON.ObjectId(), - name: "Schedule a meeting", + // Complete high-priority item + _id: new BSON.ObjectId(), + name: "Create a ticket", isComplete: true, assignee: "Chris", priority: 9, progressMinutes: 10, }, { - _id: new Realm.BSON.ObjectId(), - name: "Get coffee", + // Incomplete high-priority item + _id: new BSON.ObjectId(), + name: "Demo template app", isComplete: false, assignee: "Dachary", priority: 11, progressMinutes: 3, }, ], + quota: 1, // meets quota + comments: { status: "Ahead of schedule", projectNumber: "70187" }, + projectLocation: mainBranch, }); - const proj2 = realm.create("Project", { - _id: new Realm.BSON.ObjectId(), - name: "Another project", - items: [proj1.items[2]], - }); - - realm.create("Item", { - _id: new Realm.BSON.ObjectId(), - name: "Assign me to a project", - isComplete: false, - assignee: "Nick", - priority: 2, - progressMinutes: 0, + realm.create(Project, { + _id: new BSON.ObjectId(), + name: "Project in Austin", + items: [ + project.items[0], + { + // Incomplete high-priority item assigned to `nil` type + _id: new BSON.ObjectId(), + name: "Lead offsite workshop", + isComplete: false, + assignee: "nil", + priority: 10, + progressMinutes: 0, + }, + ], + quota: 11, // doesn't meet quota + comments: { status: "On track", projectNumber: "N/A" }, + projectLocation: austinBranch, }); }); - - expect(realm.objects("Project")[0].name).toBe("New Project"); - expect(realm.objects("Item")[0].name).toBe("Write tests"); }); afterEach(() => { @@ -100,37 +133,788 @@ describe("Realm Query Language Reference", () => { realm.deleteAll(); }); realm.close(); + expect(realm.isClosed).toBe(true); } }); - test("full-text search", () => { + afterAll(() => { + Realm.deleteFile(config); + }); + + test("Can open realm and create objects", async () => { + expect(realm.isClosed).toBe(false); + expect(realm.objects(Project)[0].name).toBe("Example Project with Items"); + expect(realm.objects(Item)[0].name).toBe("Write tests"); + }); + + test("Simple query", () => { + // NOTE: snippet used on Node.js Query Data page, not RQL page + // :snippet-start: simple-query const items = realm.objects(Item); + // Get all items where 'priority' property is 7 or more. + const importantItems = items.filtered("priority >= $0", 7); + // :snippet-end: + expect(importantItems.length).toEqual(5); + }); - const itemsWithWrite = items.filtered( - // :snippet-start: rql-fts - // Filter for items with 'write' in the name - "name TEXT $0", "write" + describe("Basic syntax", () => { + test("Expression query", () => { + const items = realm.objects(Item); + // :snippet-start: predicate + const expression = "priority == 1"; + // :snippet-end: + expect(items.filtered(expression).length).toBe(1); + }); + test("Serialized query", () => { + const items = realm.objects(Item); + const query = items.filtered( + // :snippet-start: serialized-query + "progressMinutes > 1 AND assignee == 'Ali'" + // :snippet end: + ); + expect(query.length).toBe(1); + }); + test("Parameterized query", () => { + const items = realm.objects(Item); + const substitution = items.filtered( + // :snippet-start: parameterized-query + // Include one parameter with `$0`. + "progressMinutes > 1 AND assignee == $0", + "Ali" + // :remove-start: + ); + expect(substitution.length).toBe(1); + }); + + test("Multiple parameterized query", () => { + const items = realm.objects(Item); + const substitution = items.filtered( + // :remove-end: + + // Include multiple parameters using ascending integers, + // starting at`$0`. + "progressMinutes > $0 AND assignee == $1", + 1, + "Alex" + // :snippet-end: + ); + expect(substitution.length).toBe(1); + }); + + test("Dot notation", () => { + const address = realm.objects(Project); + const nestedMatch = address.filtered( + // :snippet-start: deep-dot-notation + "projectLocation.address.zipcode == 10019" + // :snippet-end: + ); + expect(nestedMatch.length).toBe(3); + }); + }); + + test("Comparison operators", () => { + const items = realm.objects(Item); + + const highPriorityItems = items.filtered( + // :snippet-start: comparison-operators + // Find high-priority to-do items: + // Compare `priority` values against a threshold value, + // above which is considered high. + "priority > $0", + 5 + // :remove-start: + ); + expect(highPriorityItems.length).toBe(5); + + const longRunningItems = items.filtered( + // :remove-end: + // Find long-running to-do items: + // Compare `progressMinutes` values against a threshold value, + // where items at or above are considered long running. + "progressMinutes > $0", + 120 + // :remove-start: + ); + expect(longRunningItems.length).toBe(1); + + const unassignedItems = items.filtered( + // :remove-end: + + // Find unassigned to-do items: + // Compare `assignee` values to `null` value. + "assignee == $0", + null + // :remove-start: + ); + expect(unassignedItems.length).toBe(1); + + const progressMinutesRange = items.filtered( + // :remove-end: + + // Find low-priority to-do items: + // Compare `priority` values against an inclusive range of values. + "priority BETWEEN { $0 , $1 }", + 1, + 5 + // :remove-start: + ); + expect(progressMinutesRange.length).toBe(2); + + const progressMinutesIn = items.filtered( + // :remove-end: + + // Find to-do items with specific progress times: + // Compare `progressMinutes` values against any of the listed values. + "progressMinutes IN { $0, $1, $2 }", + 10, + 30, + 60 + // :snippet-end: + ); + expect(progressMinutesIn.length).toBe(2); + }); + + test("Logical operators", () => { + const items = realm.objects(Item); + const aliComplete = items.filtered( + // :snippet-start: logical-operators + // Find all to-do items assigned to Ali AND are completed. + "assignee == $0 AND isComplete == $1", + "Ali", + true + // :remove-start: + ); + const alexOrAli = items.filtered( + // :remove-end: + // Find all to-do items assigned to Alex OR to Ali. + "assignee == $0 OR assignee == $1", + "Alex", + "Ali" + // :snippet-end: + ); + expect(aliComplete.length).toBe(0); + expect(alexOrAli.length).toBe(2); + }); + + describe("Arithmetic operators", () => { + test("Basic arithmetic", () => { + const items = realm.objects(Item); + const basicMath = items.filtered( + // :snippet-start: basic-arithmetic + "2 * priority > 6" // :remove-start: ); + const lessBasicMath = items.filtered( + // :remove-end: + // Is equivalent to + "priority >= 2 * (2 - 1) + 2" + // :snippet-end: + ); - const itemsWithWriteNotTest = items.filtered( + expect(basicMath.length).toBe(6); + expect(lessBasicMath.length).toBe(6); + }); + + test("Arithmetic with object properties", () => { + const items = realm.objects(Item); + const mathWithObjProps = items.filtered( + // :snippet-start: arithmetic-obj-properties + "progressMinutes * priority == 90" + // :snippet-end: + ); + expect(mathWithObjProps.length).toBe(2); + }); + }); + + describe("Type-specific operators", () => { + test("String operators", () => { + const projects = realm.objects(Project); + const startWithE = projects.filtered( + // :snippet-start: string-operators + // Find projects whose name starts with the letter 'e' (case-insensitive). + "name BEGINSWITH[c] $0", + "e" + // :remove-start: + ); + expect(startWithE.length).toBe(1); + + const containIe = projects.filtered( + // :remove-end: + + // Find projects whose name contains the letters 'ie' (case-sensitive). + "name CONTAINS $0", + "ie" + // :snippet-end: + ); + expect(containIe.length).toBe(0); + }); + }); + + test("Aggregate queries", () => { + const projects = realm.objects(Project); + + // :snippet-start: aggregate-operators + var priorityNum = 5; + + // :remove-start: + const averageItemPriorityAbove5 = projects.filtered( + // :remove-end: + // Find projects with average item `priority` above 5. + "items.@avg.priority > $0", + priorityNum + // :remove-start: + ); + expect(averageItemPriorityAbove5.length).toBe(3); + + const allItemsLowerPriority = projects.filtered( + // :remove-end: + + // Find projects with a maximum `priority` of 5 (all items must be less + // than 5). + "items.@max.priority < $0", + priorityNum + // :remove-start: + ); + expect(allItemsLowerPriority.length).toBe(0); + + const allItemsHighPriority = projects.filtered( + // :remove-end: + + // Find projects with a minimum `priority` of 5 (all items must be greater + // than 5). + "items.@min.priority > $0", + priorityNum + // :remove-start: + ); + expect(allItemsHighPriority.length).toBe(0); + + const moreThan5Items = projects.filtered( + // :remove-end: + + // Find projects with more than 5 items. + "items.@count > $0", + 5 + // :remove-start: + ); + expect(moreThan5Items.length).toBe(0); + + const longRunningProjects = projects.filtered( + // :remove-end: + + // Find projects with item `progressMinutes` greater than 100. + "items.@sum.progressMinutes > $0", + 100 + // :snippet-end: + ); + expect(longRunningProjects.length).toBe(1); + }); + + describe("Collection queries", () => { + test("Collection operators", () => { + const projects = realm.objects(Project); + const noCompleteItems = projects.filtered( + // :snippet-start: set-operators + // Projects with no complete items. + "NONE items.isComplete == $0", + true + // :remove-start: + ); + + const anyTopPriorityItems = projects.filtered( // :remove-end: - // Find items with 'write' but not 'tests' using '-' - "name TEXT $0", "write -tests" + // Projects that contain an item with priority 10. + "ANY items.priority == $0", + 10 // :remove-start: ); + const allItemsCompleted = projects.filtered( + // :remove-end: - const itemsStartingWithWri = items.filtered( + // Projects that only contain completed items. + "ALL items.isComplete == $0", + true + // :remove-start: + ); + const assignedToAlexOrAli = projects.filtered( // :remove-end: - // Find items starting with 'wri-' using '*' - "name TEXT $0", "wri*" + + // Projects with at least one item assigned to either Alex or Ali. + "ANY items.assignee IN { $0 , $1 }", + "Alex", + "Ali" + // :remove-start: + ); + const notAssignedToAlexOrAli = projects.filtered( + // :remove-end: + + // Projects with no items assigned to either Alex or Ali. + "NONE items.assignee IN { $0 , $1 }", + "Alex", + "Ali" + // :snippet-end: + ); + expect(noCompleteItems.length).toBe(1); + expect(anyTopPriorityItems.length).toBe(1); + expect(allItemsCompleted.length).toBe(0); + expect(assignedToAlexOrAli.length).toBe(1); + expect(notAssignedToAlexOrAli.length).toBe(2); + }); + + test("List comparisons", () => { + realm.write(() => {}); + const projects = realm.objects(Project); + const items = realm.objects(Item); + + const collectionQuery = projects.filtered( + // :snippet-start: list-comparisons-collection + "oid(631a072f75120729dc9223d9) IN items._id" + // :snippet-end: + ); + const staticQuery = items.filtered( + // :snippet-start: list-comparisons-static + "priority IN {0, 1, 2}" + // :snippet-end: + ); + // :snippet-start: list-comparisons-parameterized + const ids = [ + new BSON.ObjectId("631a072f75120729dc9223d9"), + new BSON.ObjectId("631a0737c98f89f5b81cd24d"), + new BSON.ObjectId("631a073c833a34ade21db2b2"), + ]; + const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); + // :snippet-end: + + expect(collectionQuery.length).toBe(1); + expect(staticQuery.length).toBe(1); + expect(parameterizedQuery.length).toBe(3); + }); + + test("Sort, distinct, and limit results", () => { + const items = realm.objects(Item); + + const sortedUniqueAliItems = items.filtered( + // :snippet-start: sort-distinct-limit + "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" + // :snippet-end: + ); + expect(sortedUniqueAliItems.length).toBe(1); + }); + + test("Subquery queries", () => { + const projects = realm.objects(Project); + const subquery = projects.filtered( + // :snippet-start: subquery + // Find projects with incomplete to-do items assigned to Alex. + "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" // :snippet-end: ); + expect(subquery.length).toBe(1); + expect(subquery[0].name).toBe("Example Project with Items"); + + const subquery2 = projects.filtered( + // :snippet-start: subquery-count + // Find projects where the number of completed to-do items + // is greater than or equal to the project's `quota` property. + "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" + // :snippet-end: + ); + expect(subquery2.length).toBe(1); + expect(subquery2[0].name).toBe("Project that Meets Quota"); + }); + + test("Dictionary operators", () => { + const dictionaries = realm.objects(Project); + + const statusKey = dictionaries.filtered( + // :snippet-start: dictionary-operators + // Finds `comments` dictionary properties with key 'status' + "comments.@keys == $0", + "status" + + // :remove-start: + ); + const statusOnTrack = dictionaries.filtered( + // :remove-end: + // Find `comments` dictionary properties with key 'status' + // and value 'On track' + "comments['status'] == $0", + "On track" + // :remove-start: + ); + const numItemsInDict = dictionaries.filtered( + // :remove-end: + // Finds `comments` dictionary properties with + // more than one key-value pair + "comments.@count > $0", + 1 + + // :remove-start: + ); + + const hasString = dictionaries.filtered( + // :remove-end: + //Find `comments` dictionary properties where ANY + // values are of type 'string` + "ANY comments.@type == 'string'" + // :remove-start: + ); + + const hasStringImplied = dictionaries.filtered( + // :remove-end: + "comments.@type == 'string'" // (Equivalent - ANY is implied.) + + // :remove-start: + ); + + const allInt = dictionaries.filtered( + // :remove-end: + // Finds `comments` dictionary properties where ALL + // values are of type 'int' + "ALL comments.@type == 'int'" + + // :remove-start: + ); + + const noInts = dictionaries.filtered( + // :remove-end: + // Finds `comments` dictionary properties where NO + // values are of type 'int' + "NONE comments.@type == 'int'" + + // :remove-start: + ); + + expect(statusKey.length).toBe(3); + expect(statusOnTrack.length).toBe(1); + expect(numItemsInDict.length).toBe(3); + expect(hasString.length).toBe(3); + expect(hasStringImplied.length).toBe(3); + expect(allInt.length).toBe(0); + expect(noInts.length).toBe(3); + }); + }); + + describe("Backlinks queries", () => { + test("Backlinks query @links", () => { + const atLinksResult = realm.objects(Item).filtered( + // :snippet-start: backlinks-atLinks + // Find items that belong to a project with a quota less than 10 (@links) + "@links.Project.items.quota < 10" + // :snippet-end: + ); + expect(atLinksResult.length).toBe(5); + + const linkingObjectsResult = realm.objects(Item).filtered( + // :snippet-start: backlinks-linkingObjects + // Find items that belong to a project with a quota greater than 10 (LinkingObjects) + "projects.quota > 10" + // :snippet-end: + ); + expect(linkingObjectsResult.length).toBe(2); + }); + + test("Backlinks collection operators", () => { + const anyResult = realm.objects(Item).filtered( + // :snippet-start: backlinks-collection-operators + // Find items where any project that references the item has a quota greater than 10. + "ANY @links.Project.items.quota > 10" + // :remove-start: + ); + expect(anyResult.length).toBe(2); + + const allResult = realm.objects(Item).filtered( + // :remove-end: + // Find items where all projects that reference the item have a quota + // less than 5. + "ALL @links.Project.items.quota < 5" + // :snippet-end: + ); + expect(allResult.length).toBe(5); + }); + + test("Backlinks aggregate operators", () => { + const shallowResultLinkingObjects = realm.objects(Item).filtered( + // :snippet-start: backlinks-aggregate-operators + // Find items that are referenced by multiple projects + "projects.@count > 1" + // :remove-start: + ); + expect(shallowResultLinkingObjects.length).toBe(1); + expect(shallowResultLinkingObjects[0].name).toBe("Approve project plan"); + + const shallowResultAtLinks = realm.objects(Item).filtered( + // :remove-end: + // Find items that are not referenced by any project + "@links.Project.items.@count == 0" + // :remove-start: + ); + expect(shallowResultAtLinks.length).toBe(1); + expect(shallowResultAtLinks[0].name).toBe("Write tests"); + + const deepResultAtLinks = realm.objects(Item).filtered( + // :remove-end: + // Find items that belong to a project where the average item has + // been worked on for at least 5 minutes + "@links.Project.items.items.@avg.progressMinutes > 10" + // :snippet-end: + ); + expect(deepResultAtLinks.length).toBe(2); + expect(deepResultAtLinks[0].name).toBe("Write tests"); + }); + + test("Count all backlinks (@links.@count)", () => { + const result = realm.objects(Item).filtered( + // :snippet-start: backlinks-atCount + // Find items that are not referenced by another object of any type + "@links.@count == 0" + // :snippet-end: + ); + expect(result.length).toBe(1); + expect(result[0].name).toBe("Write tests"); + }); + }); + + describe("Type operator", () => { + // Uses a test-specific schema with mixed type + // TODO: Update main schema with mixed type property once collections-in-mixed is supported + const Mixed = { + name: "Mixed", + properties: { name: "string", mixedType: "mixed" }, + }; + let realm; + const path = "mixed.realm"; + + // Add, then delete objects for this test + beforeEach(async () => { + realm = await Realm.open({ + schema: [Mixed], + path, + }); + realm.write(() => { + realm.create("Mixed", { + name: "Marge", + mixedType: true, + }); + realm.create("Mixed", { + name: "Lisa", + mixedType: 22, + }); + realm.create("Mixed", { + name: "Bart", + mixedType: "carrumba", + }); + }); + }); + + afterEach(() => { + realm.close(); + Realm.deleteFile({ path }); + }); + + test("Type operator", () => { + const mixed = realm.objects("Mixed"); + const mixedString = mixed.filtered( + // :snippet-start: type-operator + "mixedType.@type == 'string'" + // :remove-start: + ); + const mixedBool = mixed.filtered( + // :remove-end: + + "mixedType.@type == 'bool'" + // :snippet-end: + ); + expect(mixedString.length).toBe(1); + expect(mixedBool.length).toBe(1); + }); + }); + + test("Nil type", () => { + const items = realm.objects(Item); + const res = items.filtered( + // :snippet-start: nil-type + "assignee == nil" + // :snippet-end: + ); + + const res2 = realm.objects(Item).filtered( + // :snippet-start: nil-type-parameterized-query + // comparison to language null pointer + "assignee == $0", + null + // :snippet-end: + ); + + expect(res.length).toBe(1); + expect(res2.length).toBe(1); + }); + + describe("ObjectId and UUID queries", () => { + // Uses a test-specific schema with id types + const OidUuid = { + name: "OidUuid", + properties: { id: "uuid", _id: "objectId" }, + }; + + let realm; + const path = "oidUuid.realm"; + + const oidValueString = "6001c033600510df3bbfd864"; + const uuid1String = "d1b186e1-e9e0-4768-a1a7-c492519d47ee"; + const oidValue = new BSON.ObjectId(oidValueString); + const uuid1 = new BSON.UUID(uuid1String); + + // Add, then delete objects for this test + beforeEach(async () => { + realm = await Realm.open({ schema: [OidUuid], path }); + const obj1 = { + _id: oidValue, + id: uuid1, + }; + const obj2 = { + _id: new BSON.ObjectId(), + id: new BSON.UUID(), + }; + realm.write(() => { + realm.create("OidUuid", obj1); + realm.create("OidUuid", obj2); + }); + }); + + afterEach(() => { + realm.close(); + Realm.deleteFile({ path }); + }); + + test("ObjectId Operator", () => { + const oidUuids = realm.objects("OidUuid"); + const oidStringLiteral = oidUuids.filtered( + // :snippet-start: oid + "_id == oid(6001c033600510df3bbfd864)" + // :snippet-end: + ); + const oidInterpolation = oidUuids.filtered( + // :snippet-start:oid-literal + "_id == $0", + oidValue + // :snippet-end: + ); + + expect(oidStringLiteral.length).toBe(1); + expect(oidInterpolation.length).toBe(1); + }); + test("UUID Operator", () => { + const oidUuids = realm.objects("OidUuid"); + const uuid = oidUuids.filtered( + // :snippet-start: uuid + "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" + // :snippet-end: + ); + expect(uuid.length).toBe(1); + }); + }); + + describe("Date queries", () => { + // Uses a test-specific schema with Date type + const DateTime = { + name: "Date", + properties: { name: "string", dateCompleted: "date" }, + }; + + let realm; + const path = "date.realm"; + + // Add, then delete Date objects for this test + beforeEach(async () => { + realm = await Realm.open({ + schema: [DateTime], + path, + }); + + realm.write(() => { + realm.create("Date", { + name: "now", + dateCompleted: new Date(), + }); + realm.create("Date", { + name: "past", + dateCompleted: new Date("December 17, 1985 03:24:00"), + }); + realm.create("Date", { + name: "withinYear", + dateCompleted: new Date("February 17, 2021 03:24:00"), + }); + }); + }); + + afterEach(() => { + realm.close(); + Realm.deleteFile({ path }); + }); + + test("Date queries", () => { + const dates = realm.objects("Date"); + // :snippet-start: date-alt-representation + var today = new Date("April 01, 2021 03:24:00"); + + var thisYear = new Date("2021-01-01@17:30:15:0"); + // :snippet-end: + const dateParameterizedQuery = dates.filtered( + // :snippet-start: date-parameterized-query + // Find to-do items completed before today's date. + "dateCompleted < $0", + today + + // :remove-start: + ); + + const dateAlt1 = dates.filtered( + // :remove-end: + // Find to-do items completed this year up to today. + "dateCompleted > $0 AND dateCompleted < $1", + thisYear, + today + // :snippet-end: + ); + + expect(dateParameterizedQuery.length).toBe(2); + expect(dateAlt1.length).toBe(1); + }); + }); + + test("Full-text search (FTS) query", () => { + const items = realm.objects(Item); + + const itemsWithWrite = items.filtered( + // :snippet-start: rql-fts + // Filter for items with 'write' in the name + "name TEXT $0", + "write" + + // :remove-start: + ); + + const itemsWithWriteNotTest = items.filtered( + // :remove-end: + // Find items with 'write' but not 'tests' using '-' + "name TEXT $0", + "write -tests" + + // :remove-start: + ); + + const itemsStartingWithWri = items.filtered( + // :remove-end: + // Find items starting with 'wri-' using '*' + "name TEXT $0", + "wri*" + // :snippet-end: + ); - expect(itemsWithWrite.length).toBe(1) + expect(itemsWithWrite.length).toBe(2); expect(itemsWithWriteNotTest.length).toBe(0); - expect(itemsStartingWithWri.length).toBe(1); + expect(itemsStartingWithWri.length).toBe(2); }); -}); \ No newline at end of file +}); From b610f1911e5e58bf9c5c2817b7fea7467a0acd24 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 21 May 2024 09:14:08 -0400 Subject: [PATCH 02/12] Update comment in legacy files --- .../node/legacy/Examples/realm-query-language.js | 13 ++++++++----- examples/node/legacy/Examples/rql-data-models.js | 7 +++++++ .../node/legacy/Examples/schemas/rql-data-models.js | 6 ++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/examples/node/legacy/Examples/realm-query-language.js b/examples/node/legacy/Examples/realm-query-language.js index 305e8ccab2..e7a1e8eb41 100644 --- a/examples/node/legacy/Examples/realm-query-language.js +++ b/examples/node/legacy/Examples/realm-query-language.js @@ -1,9 +1,12 @@ import Realm, { BSON } from "realm"; import { ItemModel, ProjectModel } from "./schemas/rql-data-models"; -// Tests for new RQL operators or updates should be placed in the new -// file compatible with JSv12 and later, located at -// examples/node/v12/__tests__/realm-query-language.test.js +/* + DON'T UPDATE THIS FILE. DEPRECATED IN FAVOR OF V12 TESTS. + Tests for new RQL operators or updates should be placed in the new + files compatible with JSv12 and later, located at: + examples/node/v12/__tests__/realm-query-language.test.js/ts +*/ describe("Realm Query Language Reference", () => { let realm; @@ -148,7 +151,7 @@ describe("Realm Query Language Reference", () => { const progressMinutesRange = items.filtered( // :remove-end: - // Find to-do items within a certain time range by finding items + // Find to-do items within a certain time range by finding items // where the progressMinutes property is between two numbers. "progressMinutes BETWEEN { $0 , $1 }", 30, 60 // :remove-start: @@ -406,7 +409,7 @@ describe("Realm Query Language Reference", () => { ); expect(shallowResultLinkingObjects.length).toBe(1); expect(shallowResultLinkingObjects[0].name).toBe("Get coffee"); - + const shallowResultAtLinks = realm.objects("Item").filtered( // :remove-end: // Find items that are not referenced by any project diff --git a/examples/node/legacy/Examples/rql-data-models.js b/examples/node/legacy/Examples/rql-data-models.js index 8277722b6e..4cc90a4b90 100644 --- a/examples/node/legacy/Examples/rql-data-models.js +++ b/examples/node/legacy/Examples/rql-data-models.js @@ -1,6 +1,13 @@ import Realm from "realm"; import { ItemModel, ProjectModel } from "./schemas/rql-data-models"; +/* + DON'T UPDATE THIS FILE. DEPRECATED IN FAVOR OF V12 TESTS. + Updates should be placed in the new files compatible with + JSv12 and later, located at: + examples/node/v12/__tests__/rql-data-models.test.js/ts +*/ + describe("test models", () => { let realm; const config = { diff --git a/examples/node/legacy/Examples/schemas/rql-data-models.js b/examples/node/legacy/Examples/schemas/rql-data-models.js index 0e2cd9a02f..9c136650e5 100644 --- a/examples/node/legacy/Examples/schemas/rql-data-models.js +++ b/examples/node/legacy/Examples/schemas/rql-data-models.js @@ -1,3 +1,9 @@ +/* + DON'T UPDATE THIS FILE. DEPRECATED IN FAVOR OF V12 MODELS. + Updates should be placed in the new file compatible with + JSv12 and later, located at: + examples/node/v12/__tests__/models/rql-data-models.ts +*/ // :snippet-start: rql-data-models const ItemModel = { name: "Item", From 41129af78a4dcc07274d4f53a2fbaa88eb047228 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 21 May 2024 09:39:33 -0400 Subject: [PATCH 03/12] Apply prettier-ignore and reformat parameterized queries --- .../__tests__/realm-query-language.test.js | 354 +++++++++--------- 1 file changed, 170 insertions(+), 184 deletions(-) diff --git a/examples/node/v12/__tests__/realm-query-language.test.js b/examples/node/v12/__tests__/realm-query-language.test.js index 4b0a0c2c9d..8110961261 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.js +++ b/examples/node/v12/__tests__/realm-query-language.test.js @@ -1,8 +1,8 @@ -/* eslint-disable prettier/prettier */ import Realm, { BSON } from "realm"; import { Address, Item, Office, Project } from "./models/rql-data-models.ts"; import { describe, expect } from "@jest/globals"; +// Note: Snippets generated from TypeScript test file describe("Realm Query Language Reference", () => { let realm; const config = { schema: [Project, Item, Address, Office] }; @@ -149,54 +149,53 @@ describe("Realm Query Language Reference", () => { test("Simple query", () => { // NOTE: snippet used on Node.js Query Data page, not RQL page - // :snippet-start: simple-query + // [snippet-start] simple-query const items = realm.objects(Item); // Get all items where 'priority' property is 7 or more. const importantItems = items.filtered("priority >= $0", 7); - // :snippet-end: + // [snippet-end] expect(importantItems.length).toEqual(5); }); describe("Basic syntax", () => { test("Expression query", () => { const items = realm.objects(Item); - // :snippet-start: predicate + // [snippet-start] predicate const expression = "priority == 1"; - // :snippet-end: + // [snippet-end] expect(items.filtered(expression).length).toBe(1); }); test("Serialized query", () => { const items = realm.objects(Item); const query = items.filtered( - // :snippet-start: serialized-query + // [snippet-start] serialized-query "progressMinutes > 1 AND assignee == 'Ali'" - // :snippet end: + // [snippet-end] ); expect(query.length).toBe(1); }); test("Parameterized query", () => { const items = realm.objects(Item); + // prettier-ignore const substitution = items.filtered( - // :snippet-start: parameterized-query + // [snippet-start] parameterized-query // Include one parameter with `$0`. - "progressMinutes > 1 AND assignee == $0", - "Ali" - // :remove-start: + "progressMinutes > 1 AND assignee == $0", "Ali" + // [remove-start] ); expect(substitution.length).toBe(1); }); test("Multiple parameterized query", () => { const items = realm.objects(Item); + // prettier-ignore const substitution = items.filtered( - // :remove-end: + // [remove-end] // Include multiple parameters using ascending integers, // starting at`$0`. - "progressMinutes > $0 AND assignee == $1", - 1, - "Alex" - // :snippet-end: + "progressMinutes > $0 AND assignee == $1", 1, "Alex" + // [snippet-end] ); expect(substitution.length).toBe(1); }); @@ -204,94 +203,87 @@ describe("Realm Query Language Reference", () => { test("Dot notation", () => { const address = realm.objects(Project); const nestedMatch = address.filtered( - // :snippet-start: deep-dot-notation + // [snippet-start] deep-dot-notation "projectLocation.address.zipcode == 10019" - // :snippet-end: + // [snippet-end] ); expect(nestedMatch.length).toBe(3); }); }); + // prettier-ignore test("Comparison operators", () => { const items = realm.objects(Item); const highPriorityItems = items.filtered( - // :snippet-start: comparison-operators + // [snippet-start] comparison-operators // Find high-priority to-do items: // Compare `priority` values against a threshold value, // above which is considered high. "priority > $0", 5 - // :remove-start: + // [remove-start] ); expect(highPriorityItems.length).toBe(5); const longRunningItems = items.filtered( - // :remove-end: + // [remove-end] // Find long-running to-do items: // Compare `progressMinutes` values against a threshold value, // where items at or above are considered long running. "progressMinutes > $0", 120 - // :remove-start: + // [remove-start] ); expect(longRunningItems.length).toBe(1); const unassignedItems = items.filtered( - // :remove-end: + // [remove-end] // Find unassigned to-do items: // Compare `assignee` values to `null` value. - "assignee == $0", - null - // :remove-start: + "assignee == $0", null + // [remove-start] ); expect(unassignedItems.length).toBe(1); const progressMinutesRange = items.filtered( - // :remove-end: + // [remove-end] // Find low-priority to-do items: // Compare `priority` values against an inclusive range of values. - "priority BETWEEN { $0 , $1 }", - 1, - 5 - // :remove-start: + "priority BETWEEN { $0 , $1 }", 1, 5 + // [remove-start] ); expect(progressMinutesRange.length).toBe(2); const progressMinutesIn = items.filtered( - // :remove-end: + // [remove-end] // Find to-do items with specific progress times: // Compare `progressMinutes` values against any of the listed values. - "progressMinutes IN { $0, $1, $2 }", - 10, - 30, - 60 - // :snippet-end: + "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 + // [snippet-end] ); expect(progressMinutesIn.length).toBe(2); }); + // prettier-ignore test("Logical operators", () => { const items = realm.objects(Item); const aliComplete = items.filtered( - // :snippet-start: logical-operators + // [snippet-start] logical-operators // Find all to-do items assigned to Ali AND are completed. - "assignee == $0 AND isComplete == $1", - "Ali", - true - // :remove-start: + "assignee == $0 AND isComplete == $1", "Ali", true + // [remove-start] ); + const alexOrAli = items.filtered( - // :remove-end: + // [remove-end] // Find all to-do items assigned to Alex OR to Ali. - "assignee == $0 OR assignee == $1", - "Alex", - "Ali" - // :snippet-end: + "assignee == $0 OR assignee == $1", "Alex", "Ali" + // [snippet-end] ); expect(aliComplete.length).toBe(0); expect(alexOrAli.length).toBe(2); @@ -301,15 +293,15 @@ describe("Realm Query Language Reference", () => { test("Basic arithmetic", () => { const items = realm.objects(Item); const basicMath = items.filtered( - // :snippet-start: basic-arithmetic + // [snippet-start] basic-arithmetic "2 * priority > 6" - // :remove-start: + // [remove-start] ); const lessBasicMath = items.filtered( - // :remove-end: + // [remove-end] // Is equivalent to "priority >= 2 * (2 - 1) + 2" - // :snippet-end: + // [snippet-end] ); expect(basicMath.length).toBe(6); @@ -319,141 +311,139 @@ describe("Realm Query Language Reference", () => { test("Arithmetic with object properties", () => { const items = realm.objects(Item); const mathWithObjProps = items.filtered( - // :snippet-start: arithmetic-obj-properties + // [snippet-start] arithmetic-obj-properties "progressMinutes * priority == 90" - // :snippet-end: + // [snippet-end] ); expect(mathWithObjProps.length).toBe(2); }); }); + // prettier-ignore describe("Type-specific operators", () => { test("String operators", () => { const projects = realm.objects(Project); const startWithE = projects.filtered( - // :snippet-start: string-operators - // Find projects whose name starts with the letter 'e' (case-insensitive). - "name BEGINSWITH[c] $0", - "e" - // :remove-start: + // [snippet-start] string-operators + // Find projects whose name starts with the letter 'e' + // (case-insensitive). + "name BEGINSWITH[c] $0", "e" + // [remove-start] ); expect(startWithE.length).toBe(1); const containIe = projects.filtered( - // :remove-end: + // [remove-end] - // Find projects whose name contains the letters 'ie' (case-sensitive). - "name CONTAINS $0", - "ie" - // :snippet-end: + // Find projects whose name contains the letters 'ie' + // (case-sensitive). + "name CONTAINS $0", "ie" + // [snippet-end] ); expect(containIe.length).toBe(0); }); }); + // prettier-ignore test("Aggregate queries", () => { const projects = realm.objects(Project); - // :snippet-start: aggregate-operators + // [snippet-start] aggregate-operators var priorityNum = 5; - // :remove-start: + // [remove-start] const averageItemPriorityAbove5 = projects.filtered( - // :remove-end: + // [remove-end] // Find projects with average item `priority` above 5. - "items.@avg.priority > $0", - priorityNum - // :remove-start: + "items.@avg.priority > $0", priorityNum + // [remove-start] ); expect(averageItemPriorityAbove5.length).toBe(3); const allItemsLowerPriority = projects.filtered( - // :remove-end: + // [remove-end] // Find projects with a maximum `priority` of 5 (all items must be less // than 5). - "items.@max.priority < $0", - priorityNum - // :remove-start: + "items.@max.priority < $0", priorityNum + // [remove-start] ); expect(allItemsLowerPriority.length).toBe(0); const allItemsHighPriority = projects.filtered( - // :remove-end: + // [remove-end] // Find projects with a minimum `priority` of 5 (all items must be greater // than 5). - "items.@min.priority > $0", - priorityNum - // :remove-start: + "items.@min.priority > $0", priorityNum + // [remove-start] ); expect(allItemsHighPriority.length).toBe(0); const moreThan5Items = projects.filtered( - // :remove-end: + // [remove-end] // Find projects with more than 5 items. - "items.@count > $0", - 5 - // :remove-start: + "items.@count > $0", 5 + // [remove-start] ); expect(moreThan5Items.length).toBe(0); const longRunningProjects = projects.filtered( - // :remove-end: + // [remove-end] // Find projects with item `progressMinutes` greater than 100. - "items.@sum.progressMinutes > $0", - 100 - // :snippet-end: + "items.@sum.progressMinutes > $0", 100 + // [snippet-end] ); expect(longRunningProjects.length).toBe(1); }); + // prettier-ignore describe("Collection queries", () => { test("Collection operators", () => { const projects = realm.objects(Project); const noCompleteItems = projects.filtered( - // :snippet-start: set-operators + // [snippet-start] set-operators // Projects with no complete items. "NONE items.isComplete == $0", true - // :remove-start: + // [remove-start] ); const anyTopPriorityItems = projects.filtered( - // :remove-end: + // [remove-end] // Projects that contain an item with priority 10. "ANY items.priority == $0", 10 - // :remove-start: + // [remove-start] ); const allItemsCompleted = projects.filtered( - // :remove-end: + // [remove-end] // Projects that only contain completed items. "ALL items.isComplete == $0", true - // :remove-start: + // [remove-start] ); const assignedToAlexOrAli = projects.filtered( - // :remove-end: + // [remove-end] // Projects with at least one item assigned to either Alex or Ali. "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" - // :remove-start: + // [remove-start] ); const notAssignedToAlexOrAli = projects.filtered( - // :remove-end: + // [remove-end] // Projects with no items assigned to either Alex or Ali. "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" - // :snippet-end: + // [snippet-end] ); expect(noCompleteItems.length).toBe(1); expect(anyTopPriorityItems.length).toBe(1); @@ -468,23 +458,23 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const collectionQuery = projects.filtered( - // :snippet-start: list-comparisons-collection + // [snippet-start] list-comparisons-collection "oid(631a072f75120729dc9223d9) IN items._id" - // :snippet-end: + // [snippet-end] ); const staticQuery = items.filtered( - // :snippet-start: list-comparisons-static + // [snippet-start] list-comparisons-static "priority IN {0, 1, 2}" - // :snippet-end: + // [snippet-end] ); - // :snippet-start: list-comparisons-parameterized + // [snippet-start] list-comparisons-parameterized const ids = [ new BSON.ObjectId("631a072f75120729dc9223d9"), new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); - // :snippet-end: + // [snippet-end] expect(collectionQuery.length).toBe(1); expect(staticQuery.length).toBe(1); @@ -495,9 +485,9 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const sortedUniqueAliItems = items.filtered( - // :snippet-start: sort-distinct-limit + // [snippet-start] sort-distinct-limit "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" - // :snippet-end: + // [snippet-end] ); expect(sortedUniqueAliItems.length).toBe(1); }); @@ -505,85 +495,83 @@ describe("Realm Query Language Reference", () => { test("Subquery queries", () => { const projects = realm.objects(Project); const subquery = projects.filtered( - // :snippet-start: subquery + // [snippet-start] subquery // Find projects with incomplete to-do items assigned to Alex. "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" - // :snippet-end: + // [snippet-end] ); expect(subquery.length).toBe(1); expect(subquery[0].name).toBe("Example Project with Items"); const subquery2 = projects.filtered( - // :snippet-start: subquery-count + // [snippet-start] subquery-count // Find projects where the number of completed to-do items // is greater than or equal to the project's `quota` property. "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" - // :snippet-end: + // [snippet-end] ); expect(subquery2.length).toBe(1); expect(subquery2[0].name).toBe("Project that Meets Quota"); }); + // prettier-ignore test("Dictionary operators", () => { const dictionaries = realm.objects(Project); const statusKey = dictionaries.filtered( - // :snippet-start: dictionary-operators + // [snippet-start] dictionary-operators // Finds `comments` dictionary properties with key 'status' - "comments.@keys == $0", - "status" + "comments.@keys == $0", "status" - // :remove-start: + // [remove-start] ); const statusOnTrack = dictionaries.filtered( - // :remove-end: + // [remove-end] // Find `comments` dictionary properties with key 'status' // and value 'On track' - "comments['status'] == $0", - "On track" - // :remove-start: + "comments['status'] == $0", "On track" + // [remove-start] ); const numItemsInDict = dictionaries.filtered( - // :remove-end: + // [remove-end] // Finds `comments` dictionary properties with // more than one key-value pair - "comments.@count > $0", - 1 + "comments.@count > $0", 1 - // :remove-start: + // [remove-start] ); const hasString = dictionaries.filtered( - // :remove-end: + // [remove-end] //Find `comments` dictionary properties where ANY // values are of type 'string` "ANY comments.@type == 'string'" - // :remove-start: + // [remove-start] ); const hasStringImplied = dictionaries.filtered( - // :remove-end: + // [remove-end] "comments.@type == 'string'" // (Equivalent - ANY is implied.) - // :remove-start: + // [remove-start] ); const allInt = dictionaries.filtered( - // :remove-end: + // [remove-end] // Finds `comments` dictionary properties where ALL // values are of type 'int' "ALL comments.@type == 'int'" - // :remove-start: + // [remove-start] ); const noInts = dictionaries.filtered( - // :remove-end: + // [remove-end] // Finds `comments` dictionary properties where NO // values are of type 'int' "NONE comments.@type == 'int'" - // :remove-start: + // [remove-start] ); expect(statusKey.length).toBe(3); @@ -599,66 +587,66 @@ describe("Realm Query Language Reference", () => { describe("Backlinks queries", () => { test("Backlinks query @links", () => { const atLinksResult = realm.objects(Item).filtered( - // :snippet-start: backlinks-atLinks + // [snippet-start] backlinks-atLinks // Find items that belong to a project with a quota less than 10 (@links) "@links.Project.items.quota < 10" - // :snippet-end: + // [snippet-end] ); expect(atLinksResult.length).toBe(5); const linkingObjectsResult = realm.objects(Item).filtered( - // :snippet-start: backlinks-linkingObjects + // [snippet-start] backlinks-linkingObjects // Find items that belong to a project with a quota greater than 10 (LinkingObjects) "projects.quota > 10" - // :snippet-end: + // [snippet-end] ); expect(linkingObjectsResult.length).toBe(2); }); test("Backlinks collection operators", () => { const anyResult = realm.objects(Item).filtered( - // :snippet-start: backlinks-collection-operators + // [snippet-start] backlinks-collection-operators // Find items where any project that references the item has a quota greater than 10. "ANY @links.Project.items.quota > 10" - // :remove-start: + // [remove-start] ); expect(anyResult.length).toBe(2); const allResult = realm.objects(Item).filtered( - // :remove-end: + // [remove-end] // Find items where all projects that reference the item have a quota // less than 5. "ALL @links.Project.items.quota < 5" - // :snippet-end: + // [snippet-end] ); expect(allResult.length).toBe(5); }); test("Backlinks aggregate operators", () => { const shallowResultLinkingObjects = realm.objects(Item).filtered( - // :snippet-start: backlinks-aggregate-operators + // [snippet-start] backlinks-aggregate-operators // Find items that are referenced by multiple projects "projects.@count > 1" - // :remove-start: + // [remove-start] ); expect(shallowResultLinkingObjects.length).toBe(1); expect(shallowResultLinkingObjects[0].name).toBe("Approve project plan"); const shallowResultAtLinks = realm.objects(Item).filtered( - // :remove-end: + // [remove-end] // Find items that are not referenced by any project "@links.Project.items.@count == 0" - // :remove-start: + // [remove-start] ); expect(shallowResultAtLinks.length).toBe(1); expect(shallowResultAtLinks[0].name).toBe("Write tests"); const deepResultAtLinks = realm.objects(Item).filtered( - // :remove-end: + // [remove-end] // Find items that belong to a project where the average item has // been worked on for at least 5 minutes "@links.Project.items.items.@avg.progressMinutes > 10" - // :snippet-end: + // [snippet-end] ); expect(deepResultAtLinks.length).toBe(2); expect(deepResultAtLinks[0].name).toBe("Write tests"); @@ -666,10 +654,10 @@ describe("Realm Query Language Reference", () => { test("Count all backlinks (@links.@count)", () => { const result = realm.objects(Item).filtered( - // :snippet-start: backlinks-atCount + // [snippet-start] backlinks-atCount // Find items that are not referenced by another object of any type "@links.@count == 0" - // :snippet-end: + // [snippet-end] ); expect(result.length).toBe(1); expect(result[0].name).toBe("Write tests"); @@ -716,35 +704,35 @@ describe("Realm Query Language Reference", () => { test("Type operator", () => { const mixed = realm.objects("Mixed"); const mixedString = mixed.filtered( - // :snippet-start: type-operator + // [snippet-start] type-operator "mixedType.@type == 'string'" - // :remove-start: + // [remove-start] ); const mixedBool = mixed.filtered( - // :remove-end: + // [remove-end] "mixedType.@type == 'bool'" - // :snippet-end: + // [snippet-end] ); expect(mixedString.length).toBe(1); expect(mixedBool.length).toBe(1); }); }); + // prettier-ignore test("Nil type", () => { const items = realm.objects(Item); const res = items.filtered( - // :snippet-start: nil-type + // [snippet-start] nil-type "assignee == nil" - // :snippet-end: + // [snippet-end] ); const res2 = realm.objects(Item).filtered( - // :snippet-start: nil-type-parameterized-query + // [snippet-start] nil-type-parameterized-query // comparison to language null pointer - "assignee == $0", - null - // :snippet-end: + "assignee == $0", null + // [snippet-end] ); expect(res.length).toBe(1); @@ -788,30 +776,32 @@ describe("Realm Query Language Reference", () => { Realm.deleteFile({ path }); }); + // prettier-ignore test("ObjectId Operator", () => { const oidUuids = realm.objects("OidUuid"); const oidStringLiteral = oidUuids.filtered( - // :snippet-start: oid + // [snippet-start] oid "_id == oid(6001c033600510df3bbfd864)" - // :snippet-end: + // [snippet-end] ); const oidInterpolation = oidUuids.filtered( - // :snippet-start:oid-literal - "_id == $0", - oidValue - // :snippet-end: + // [snippet-start]oid-literal + "_id == $0", oidValue + // [snippet-end] ); expect(oidStringLiteral.length).toBe(1); expect(oidInterpolation.length).toBe(1); }); + test("UUID Operator", () => { const oidUuids = realm.objects("OidUuid"); const uuid = oidUuids.filtered( - // :snippet-start: uuid + // [snippet-start] uuid "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" - // :snippet-end: + // [snippet-end] ); + expect(uuid.length).toBe(1); }); }); @@ -854,29 +844,27 @@ describe("Realm Query Language Reference", () => { Realm.deleteFile({ path }); }); + // prettier-ignore test("Date queries", () => { const dates = realm.objects("Date"); - // :snippet-start: date-alt-representation + // [snippet-start] date-alt-representation var today = new Date("April 01, 2021 03:24:00"); var thisYear = new Date("2021-01-01@17:30:15:0"); - // :snippet-end: + // [snippet-end] const dateParameterizedQuery = dates.filtered( - // :snippet-start: date-parameterized-query + // [snippet-start] date-parameterized-query // Find to-do items completed before today's date. - "dateCompleted < $0", - today + "dateCompleted < $0", today - // :remove-start: + // [remove-start] ); const dateAlt1 = dates.filtered( - // :remove-end: + // [remove-end] // Find to-do items completed this year up to today. - "dateCompleted > $0 AND dateCompleted < $1", - thisYear, - today - // :snippet-end: + "dateCompleted > $0 AND dateCompleted < $1", thisYear, today + // [snippet-end] ); expect(dateParameterizedQuery.length).toBe(2); @@ -884,33 +872,31 @@ describe("Realm Query Language Reference", () => { }); }); + // prettier-ignore test("Full-text search (FTS) query", () => { const items = realm.objects(Item); const itemsWithWrite = items.filtered( - // :snippet-start: rql-fts + // [snippet-start] rql-fts // Filter for items with 'write' in the name - "name TEXT $0", - "write" + "name TEXT $0", "write" - // :remove-start: + // [remove-start] ); const itemsWithWriteNotTest = items.filtered( - // :remove-end: + // [remove-end] // Find items with 'write' but not 'tests' using '-' - "name TEXT $0", - "write -tests" + "name TEXT $0", "write -tests" - // :remove-start: + // [remove-start] ); const itemsStartingWithWri = items.filtered( - // :remove-end: + // [remove-end] // Find items starting with 'wri-' using '*' - "name TEXT $0", - "wri*" - // :snippet-end: + "name TEXT $0", "wri*" + // [snippet-end] ); expect(itemsWithWrite.length).toBe(2); From 6e29ca1fe877b3730fe4d125a14c71a03d32cf13 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 21 May 2024 10:37:04 -0400 Subject: [PATCH 04/12] Generate snippets from .ts test file --- .../__tests__/realm-query-language.test.ts | 892 ++++++++++++++++++ .../v12/__tests__/rql-data-models.test.js | 71 ++ .../v12/__tests__/rql-data-models.test.ts | 81 ++ examples/package-lock.json | 6 + ...ge.test.snippet.aggregate-operators.ts.rst | 18 + ...t.snippet.arithmetic-obj-properties.ts.rst | 3 + ...ippet.backlinks-aggregate-operators.ts.rst | 9 + ...uage.test.snippet.backlinks-atCount.ts.rst | 4 + ...uage.test.snippet.backlinks-atLinks.ts.rst | 5 + ...ppet.backlinks-collection-operators.ts.rst | 8 + ...st.snippet.backlinks-linkingObjects.ts.rst | 5 + ...guage.test.snippet.basic-arithmetic.ts.rst | 5 + ...e.test.snippet.comparison-operators.ts.rst | 16 + ...est.snippet.date-alt-representation.ts.rst | 5 + ...st.snippet.date-parameterized-query.ts.rst | 7 + ...uage.test.snippet.deep-dot-notation.ts.rst | 3 + ...e.test.snippet.dictionary-operators.ts.rst | 25 + ...snippet.list-comparisons-collection.ts.rst | 3 + ...ppet.list-comparisons-parameterized.ts.rst | 8 + ...est.snippet.list-comparisons-static.ts.rst | 3 + ...uage.test.snippet.logical-operators.ts.rst | 7 + ...nippet.nil-type-parameterized-query.ts.rst | 4 + ...uery-language.test.snippet.nil-type.ts.rst | 3 + ...y-language.test.snippet.oid-literal.ts.rst | 3 + ...alm-query-language.test.snippet.oid.ts.rst | 3 + ...ge.test.snippet.parameterized-query.ts.rst | 8 + ...ery-language.test.snippet.predicate.ts.rst | 3 + ...query-language.test.snippet.rql-fts.ts.rst | 12 + ...guage.test.snippet.serialized-query.ts.rst | 3 + ...language.test.snippet.set-operators.ts.rst | 17 + ...-language.test.snippet.simple-query.ts.rst | 5 + ...ge.test.snippet.sort-distinct-limit.ts.rst | 3 + ...guage.test.snippet.string-operators.ts.rst | 9 + ...anguage.test.snippet.subquery-count.ts.rst | 5 + ...uery-language.test.snippet.subquery.ts.rst | 4 + ...language.test.snippet.type-operator.ts.rst | 5 + ...lm-query-language.test.snippet.uuid.ts.rst | 3 + ...data-models.snippet.rql-data-models.ts.rst | 49 + 38 files changed, 1323 insertions(+) create mode 100644 examples/node/v12/__tests__/realm-query-language.test.ts create mode 100644 examples/node/v12/__tests__/rql-data-models.test.js create mode 100644 examples/node/v12/__tests__/rql-data-models.test.ts create mode 100644 examples/package-lock.json create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atCount.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts new file mode 100644 index 0000000000..fc7fa248d6 --- /dev/null +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -0,0 +1,892 @@ +import Realm, { BSON } from "realm"; +import { Address, Item, Office, Project } from "./models/rql-data-models.ts"; +import { describe, expect } from "@jest/globals"; + +describe("Realm Query Language Reference", () => { + let realm: Realm; + const config = { schema: [Project, Item, Address, Office] }; + + beforeEach(async () => { + // Before each test, open the realm and create project & item objects: + // 2 branches w/ 2 addresses; 3 projects; and + // 6 items (one used in 2 projects, another in 0 projects) + realm = await Realm.open(config); + + const mainBranch = { + name: "Main Branch", + address: { + name: "Main Branch", + street: "123 Main St", + zipcode: 10019, + }, + }; + const austinBranch = { + name: "Austin Branch", + address: { + name: "Austin Branch", + street: "123 Main Ave", + zipcode: 10019, + }, + }; + realm.write(() => { + realm.create("Item", { + // Unassigned incomplete item not in any project + _id: new BSON.ObjectId("631a073c833a34ade21db2b2"), + name: "Write tests", + isComplete: false, + assignee: null, + priority: 10, + progressMinutes: 0, + }); + + realm.create("Project", { + _id: new BSON.ObjectId(), + name: "Example Project with Items", + items: [ + { + // Alex incomplete item + _id: new BSON.ObjectId("631a072f75120729dc9223d9"), + name: "Write tests", + isComplete: false, + assignee: "Alex", + priority: 5, + progressMinutes: 125, + }, + { + // Ali incomplete item + _id: new BSON.ObjectId("631a0737c98f89f5b81cd24d"), + name: "Run tests", + isComplete: false, + assignee: "Ali", + priority: 9, + progressMinutes: 10, + }, + ], + quota: 1, // doesn't meet quota + comments: { status: "Behind schedule", projectNumber: "70150" }, + projectLocation: mainBranch, + }); + const project = realm.create("Project", { + _id: new BSON.ObjectId(), + name: "Project that Meets Quota", + items: [ + { + // Complete item used in 2 projects + _id: new BSON.ObjectId(), + name: "Approve project plan", + isComplete: true, + assignee: "Dachary", + priority: 1, + progressMinutes: 0, + }, + { + // Complete high-priority item + _id: new BSON.ObjectId(), + name: "Create a ticket", + isComplete: true, + assignee: "Chris", + priority: 9, + progressMinutes: 10, + }, + { + // Incomplete high-priority item + _id: new BSON.ObjectId(), + name: "Demo template app", + isComplete: false, + assignee: "Dachary", + priority: 11, + progressMinutes: 3, + }, + ], + quota: 1, // meets quota + comments: { status: "Ahead of schedule", projectNumber: "70187" }, + projectLocation: mainBranch, + }); + + realm.create("Project", { + _id: new BSON.ObjectId(), + name: "Project in Austin", + items: [ + project.items[0], + { + // Incomplete high-priority item assigned to `nil` type + _id: new BSON.ObjectId(), + name: "Lead offsite workshop", + isComplete: false, + assignee: "nil", + priority: 10, + progressMinutes: 0, + }, + ], + quota: 11, // doesn't meet quota + comments: { status: "On track", projectNumber: "N/A" }, + projectLocation: austinBranch, + }); + }); + }); + + afterEach(() => { + // After the test, delete the objects and close the realm + if (realm && !realm.isClosed) { + realm.write(() => { + realm.deleteAll(); + }); + realm.close(); + expect(realm.isClosed).toBe(true); + } + }); + + afterAll(() => { + Realm.deleteFile(config); + }); + + test("Can open realm and create objects", async () => { + expect(realm.isClosed).toBe(false); + expect(realm.objects(Project)[0].name).toBe("Example Project with Items"); + expect(realm.objects(Item)[0].name).toBe("Write tests"); + }); + + test("Simple query", () => { + // NOTE: snippet used on Node.js Query Data page, not RQL page + // :snippet-start: simple-query + const items = realm.objects(Item); + // Get all items where 'priority' property is 7 or more. + const importantItems = items.filtered("priority >= $0", 7); + // :snippet-end: + expect(importantItems.length).toEqual(5); + }); + + describe("Basic syntax", () => { + test("Expression query", () => { + const items = realm.objects(Item); + // :snippet-start: predicate + const expression = "priority == 1"; + // :snippet-end: + expect(items.filtered(expression).length).toBe(1); + }); + test("Serialized query", () => { + const items = realm.objects(Item); + const query = items.filtered( + // :snippet-start: serialized-query + "progressMinutes > 1 AND assignee == 'Ali'" + // :snippet-end: + ); + expect(query.length).toBe(1); + }); + test("Parameterized query", () => { + const items = realm.objects(Item); + // prettier-ignore + const substitution = items.filtered( + // :snippet-start: parameterized-query + // Include one parameter with `$0`. + "progressMinutes > 1 AND assignee == $0", "Ali" + // :remove-start: + ); + expect(substitution.length).toBe(1); + }); + + test("Multiple parameterized query", () => { + const items = realm.objects(Item); + // prettier-ignore + const substitution = items.filtered( + // :remove-end: + + // Include multiple parameters using ascending integers, + // starting at`$0`. + "progressMinutes > $0 AND assignee == $1", 1, "Alex" + // :snippet-end: + ); + expect(substitution.length).toBe(1); + }); + + test("Dot notation", () => { + const address = realm.objects(Project); + const nestedMatch = address.filtered( + // :snippet-start: deep-dot-notation + "projectLocation.address.zipcode == 10019" + // :snippet-end: + ); + expect(nestedMatch.length).toBe(3); + }); + }); + + // prettier-ignore + test("Comparison operators", () => { + const items = realm.objects(Item); + + const highPriorityItems = items.filtered( + // :snippet-start: comparison-operators + // Compare `priority` values against a threshold value. + "priority > $0", 5 + // :remove-start: + ); + expect(highPriorityItems.length).toBe(5); + + const longRunningItems = items.filtered( + // :remove-end: + + // Compare `progressMinutes` values against a threshold value. + "progressMinutes > $0", 120 + // :remove-start: + ); + expect(longRunningItems.length).toBe(1); + + const unassignedItems = items.filtered( + // :remove-end: + + // Compare `assignee` values to `null` value. + "assignee == $0", null + // :remove-start: + ); + expect(unassignedItems.length).toBe(1); + + const progressMinutesRange = items.filtered( + // :remove-end: + + // Compare `priority` values against an inclusive range of values. + "priority BETWEEN { $0 , $1 }", 1, 5 + // :remove-start: + ); + expect(progressMinutesRange.length).toBe(2); + + const progressMinutesIn = items.filtered( + // :remove-end: + + // Compare `progressMinutes` values against any of the listed values. + "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 + // :snippet-end: + ); + expect(progressMinutesIn.length).toBe(2); + }); + + // prettier-ignore + test("Logical operators", () => { + const items = realm.objects(Item); + const aliComplete = items.filtered( + // :snippet-start: logical-operators + // Find all items assigned to Ali AND marked completed. + "assignee == $0 AND isComplete == $1", "Ali", true + // :remove-start: + ); + const alexOrAli = items.filtered( + // :remove-end: + + // Find all items assigned to Alex OR to Ali. + "assignee == $0 OR assignee == $1", "Alex", "Ali" + // :snippet-end: + ); + expect(aliComplete.length).toBe(0); + expect(alexOrAli.length).toBe(2); + }); + + describe("Arithmetic operators", () => { + test("Basic arithmetic", () => { + const items = realm.objects(Item); + const basicMath = items.filtered( + // :snippet-start: basic-arithmetic + // Find items with a `priority` greater than 3. + "2 * priority > 6" // `priority > 3` + // :remove-start: + ); + const lessBasicMath = items.filtered( + // :remove-end: + "priority >= 2 * (2 - 1) + 2" // `priority >= 4` + // :snippet-end: + ); + expect(basicMath.length).toBe(6); + expect(lessBasicMath.length).toBe(6); + }); + + test("Arithmetic with object properties", () => { + const items = realm.objects(Item); + const mathWithObjProps = items.filtered( + // :snippet-start: arithmetic-obj-properties + "progressMinutes * priority == 90" + // :snippet-end: + ); + expect(mathWithObjProps.length).toBe(2); + }); + }); + + // prettier-ignore + describe("Type-specific operators", () => { + test("String operators", () => { + const projects = realm.objects(Project); + const startWithE = projects.filtered( + // :snippet-start: string-operators + // Find projects whose name starts with the letter 'e' + // (case-insensitive). + "name BEGINSWITH[c] $0", "e" + // :remove-start: + ); + expect(startWithE.length).toBe(1); + + const containIe = projects.filtered( + // :remove-end: + + // Find projects whose name contains the letters 'ie' + // (case-sensitive). + "name CONTAINS $0", "ie" + // :snippet-end: + ); + expect(containIe.length).toBe(0); + }); + }); + + // prettier-ignore + test("Aggregate queries", () => { + const projects = realm.objects(Project); + // :snippet-start: aggregate-operators + var priorityNum = 5; + + // :remove-start: + const averageItemPriorityAbove5 = projects.filtered( + // :remove-end: + // Find projects with average item `priority` above 5. + "items.@avg.priority > $0", priorityNum + // :remove-start: + ); + expect(averageItemPriorityAbove5.length).toBe(3); + + const allItemsLowerPriority = projects.filtered( + // :remove-end: + + // Find projects where maximum `priority` of all items is 5. + "items.@max.priority < $0", priorityNum + // :remove-start: + ); + expect(allItemsLowerPriority.length).toBe(0); + + const allItemsHighPriority = projects.filtered( + // :remove-end: + + // Find projects where minimum `priority` of all items is 5. + "items.@min.priority > $0", priorityNum + // :remove-start: + ); + expect(allItemsHighPriority.length).toBe(0); + + const moreThan5Items = projects.filtered( + // :remove-end: + + // Find projects with more than 5 items. + "items.@count > $0", 5 + // :remove-start: + ); + expect(moreThan5Items.length).toBe(0); + + const longRunningProjects = projects.filtered( + // :remove-end: + + // Find projects with item `progressMinutes` greater than 100. + "items.@sum.progressMinutes > $0", 100 + // :snippet-end: + ); + expect(longRunningProjects.length).toBe(1); + }); + + describe("Collection queries", () => { + test("Collection operators", () => { + const projects = realm.objects(Project); + // prettier-ignore + const noCompleteItems = projects.filtered( + // :snippet-start: set-operators + // Find projects with no complete items. + "NONE items.isComplete == $0", true + // :remove-start: + ); + // prettier-ignore + const anyTopPriorityItems = projects.filtered( + // :remove-end: + + // Find projects that contain an item with priority 10. + "ANY items.priority == $0", 10 + // :remove-start: + ); + // prettier-ignore + const allItemsCompleted = projects.filtered( + // :remove-end: + + // Find projects that only contain completed items. + "ALL items.isComplete == $0", true + // :remove-start: + ); + // prettier-ignore + const assignedToAlexOrAli = projects.filtered( + // :remove-end: + + // Find projects with at least one item assigned to + // either Alex or Ali. + "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" + // :remove-start: + ); + // prettier-ignore + const notAssignedToAlexOrAli = projects.filtered( + // :remove-end: + + // Projects with no items assigned to either Alex or Ali. + "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" + // :snippet-end: + ); + expect(noCompleteItems.length).toBe(1); + expect(anyTopPriorityItems.length).toBe(1); + expect(allItemsCompleted.length).toBe(0); + expect(assignedToAlexOrAli.length).toBe(1); + expect(notAssignedToAlexOrAli.length).toBe(2); + }); + + test("List comparisons", () => { + realm.write(() => {}); + const projects = realm.objects(Project); + const items = realm.objects(Item); + + const collectionQuery = projects.filtered( + // :snippet-start: list-comparisons-collection + "oid(631a072f75120729dc9223d9) IN items._id" + // :snippet-end: + ); + const staticQuery = items.filtered( + // :snippet-start: list-comparisons-static + "priority IN {0, 1, 2}" + // :snippet-end: + ); + // :snippet-start: list-comparisons-parameterized + const ids = [ + new BSON.ObjectId("631a072f75120729dc9223d9"), + new BSON.ObjectId("631a0737c98f89f5b81cd24d"), + new BSON.ObjectId("631a073c833a34ade21db2b2"), + ]; + const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); + // :snippet-end: + + expect(collectionQuery.length).toBe(1); + expect(staticQuery.length).toBe(1); + expect(parameterizedQuery.length).toBe(3); + }); + + test("Sort, distinct, and limit results", () => { + const items = realm.objects(Item); + + const sortedUniqueAliItems = items.filtered( + // :snippet-start: sort-distinct-limit + "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" + // :snippet-end: + ); + + expect(sortedUniqueAliItems.length).toBe(1); + }); + + test("Subquery queries", () => { + const projects = realm.objects(Project); + const subquery = projects.filtered( + // :snippet-start: subquery + // Find projects with incomplete to-do items assigned to Alex. + "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" + // :snippet-end: + ); + expect(subquery.length).toBe(1); + expect(subquery[0].name).toBe("Example Project with Items"); + + const subquery2 = projects.filtered( + // :snippet-start: subquery-count + // Find projects where the number of completed to-do items + // is greater than or equal to the project's `quota` property. + "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" + // :snippet-end: + ); + + expect(subquery2.length).toBe(1); + expect(subquery2[0].name).toBe("Project that Meets Quota"); + }); + + // prettier-ignore + test("Dictionary operators", () => { + const dictionaries = realm.objects(Project); + const statusKey = dictionaries.filtered( + // :snippet-start: dictionary-operators + // Find `comments` dictionary properties with key 'status'. + "comments.@keys == $0", "status" + + // :remove-start: + ); + const statusOnTrack = dictionaries.filtered( + // :remove-end: + // Find `comments` dictionary properties with key 'status' + // and value 'On track'. + "comments['status'] == $0", "On track" + // :remove-start: + ); + const numItemsInDict = dictionaries.filtered( + // :remove-end: + // Find `comments` dictionary properties with + // more than one key-value pair. + "comments.@count > $0", 1 + + // :remove-start: + ); + + const hasString = dictionaries.filtered( + // :remove-end: + // Find `comments` dictionary properties where ANY + // values are of type 'string`. + "ANY comments.@type == 'string'" + // :remove-start: + ); + + const hasStringImplied = dictionaries.filtered( + // :remove-end: + "comments.@type == 'string'" // (Equivalent - ANY is implied.) + + // :remove-start: + ); + + const allInt = dictionaries.filtered( + // :remove-end: + // Find `comments` dictionary properties where ALL + // values are of type 'int'. + "ALL comments.@type == 'int'" + + // :remove-start: + ); + + const noInts = dictionaries.filtered( + // :remove-end: + // Find `comments` dictionary properties where NO + // values are of type 'int'. + "NONE comments.@type == 'int'" + + // :snippet-end: + ); + + expect(statusKey.length).toBe(3); + expect(statusOnTrack.length).toBe(1); + expect(numItemsInDict.length).toBe(3); + expect(hasString.length).toBe(3); + expect(hasStringImplied.length).toBe(3); + expect(allInt.length).toBe(0); + expect(noInts.length).toBe(3); + }); + }); + + describe("Backlinks queries", () => { + test("Backlinks query @links", () => { + const atLinksResult = realm.objects(Item).filtered( + // :snippet-start: backlinks-atLinks + // Find items that belong to a project with a quota + // less than 10 (using '@links'). + "@links.Project.items.quota < 10" + // :snippet-end: + ); + expect(atLinksResult.length).toBe(5); + + const linkingObjectsResult = realm.objects(Item).filtered( + // :snippet-start: backlinks-linkingObjects + // Find items that belong to a project with a quota greater than 10 + // (using 'LinkingObjects'). + "projects.quota > 10" + // :snippet-end: + ); + expect(linkingObjectsResult.length).toBe(2); + }); + + test("Backlinks collection operators", () => { + const anyResult = realm.objects(Item).filtered( + // :snippet-start: backlinks-collection-operators + // Find items where ANY project that references the item + // has a quota greater than 10. + "ANY @links.Project.items.quota > 10" + // :remove-start: + ); + expect(anyResult.length).toBe(2); + + const allResult = realm.objects(Item).filtered( + // :remove-end: + // Find items where ALL projects that reference the item + // have a quota less than 5. + "ALL @links.Project.items.quota < 5" + // :snippet-end: + ); + expect(allResult.length).toBe(5); + }); + + test("Backlinks aggregate operators", () => { + const shallowResultLinkingObjects = realm.objects(Item).filtered( + // :snippet-start: backlinks-aggregate-operators + // Find items that are referenced by multiple projects + "projects.@count > 1" + // :remove-start: + ); + expect(shallowResultLinkingObjects.length).toBe(1); + expect(shallowResultLinkingObjects[0].name).toBe("Approve project plan"); + + const shallowResultAtLinks = realm.objects(Item).filtered( + // :remove-end: + // Find items that are not referenced by any project + "@links.Project.items.@count == 0" + // :remove-start: + ); + expect(shallowResultAtLinks.length).toBe(1); + expect(shallowResultAtLinks[0].name).toBe("Write tests"); + + const deepResultAtLinks = realm.objects(Item).filtered( + // :remove-end: + // Find items that belong to a project where the average item has + // been worked on for at least 5 minutes + "@links.Project.items.items.@avg.progressMinutes > 10" + // :snippet-end: + ); + expect(deepResultAtLinks.length).toBe(2); + expect(deepResultAtLinks[0].name).toBe("Write tests"); + }); + + test("Count all backlinks (@links.@count)", () => { + const result = realm.objects(Item).filtered( + // :snippet-start: backlinks-atCount + // Find items that are not referenced by another object of any type + "@links.@count == 0" + // :snippet-end: + ); + expect(result.length).toBe(1); + expect(result[0].name).toBe("Write tests"); + }); + }); + + describe("Type operator", () => { + // Uses a test-specific schema with mixed type + // TODO: Update main schema with mixed type property once collections-in-mixed is supported + const Mixed = { + name: "Mixed", + properties: { name: "string", mixedType: "mixed" }, + }; + let realm: Realm; + const path = "mixed.realm"; + + // Add, then delete objects for this test + beforeEach(async () => { + realm = await Realm.open({ + schema: [Mixed], + path, + }); + realm.write(() => { + realm.create("Mixed", { + name: "Marge", + mixedType: true, + }); + realm.create("Mixed", { + name: "Lisa", + mixedType: 22, + }); + realm.create("Mixed", { + name: "Bart", + mixedType: "carrumba", + }); + }); + }); + + afterEach(() => { + realm.close(); + Realm.deleteFile({ path }); + }); + + test("Type operator", () => { + const mixed = realm.objects("Mixed"); + const mixedString = mixed.filtered( + // :snippet-start: type-operator + "mixedType.@type == 'string'" + // :remove-start: + ); + const mixedBool = mixed.filtered( + // :remove-end: + + "mixedType.@type == 'bool'" + // :snippet-end: + ); + expect(mixedString.length).toBe(1); + expect(mixedBool.length).toBe(1); + }); + }); + + test("Nil type", () => { + const items = realm.objects(Item); + const res = items.filtered( + // :snippet-start: nil-type + "assignee == nil" + // :snippet-end: + ); + // prettier-ignore + const res2 = realm.objects(Item).filtered( + // :snippet-start: nil-type-parameterized-query + // comparison to language null pointer + "assignee == $0", null + // :snippet-end: + ); + + expect(res.length).toBe(1); + expect(res2.length).toBe(1); + }); + + describe("ObjectId and UUID queries", () => { + // Uses a test-specific schema with id types + const OidUuid = { + name: "OidUuid", + properties: { id: "uuid", _id: "objectId" }, + }; + + let realm: Realm; + const path = "oidUuid.realm"; + + const oidValueString = "6001c033600510df3bbfd864"; + const uuid1String = "d1b186e1-e9e0-4768-a1a7-c492519d47ee"; + const oidValue = new BSON.ObjectId(oidValueString); + const uuid1 = new BSON.UUID(uuid1String); + + // Add, then delete objects for this test + beforeEach(async () => { + realm = await Realm.open({ schema: [OidUuid], path }); + const obj1 = { + _id: oidValue, + id: uuid1, + }; + const obj2 = { + _id: new BSON.ObjectId(), + id: new BSON.UUID(), + }; + realm.write(() => { + realm.create("OidUuid", obj1); + realm.create("OidUuid", obj2); + }); + }); + + afterEach(() => { + realm.close(); + Realm.deleteFile({ path }); + }); + + test("ObjectId Operator", () => { + const oidUuids = realm.objects("OidUuid"); + const oidStringLiteral = oidUuids.filtered( + // :snippet-start: oid + "_id == oid(6001c033600510df3bbfd864)" + // :snippet-end: + ); + // prettier-ignore + const oidInterpolation = oidUuids.filtered( + // :snippet-start:oid-literal + "_id == $0", oidValue + // :snippet-end: + ); + + expect(oidStringLiteral.length).toBe(1); + expect(oidInterpolation.length).toBe(1); + }); + test("UUID Operator", () => { + const oidUuids = realm.objects("OidUuid"); + const uuid = oidUuids.filtered( + // :snippet-start: uuid + "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" + // :snippet-end: + ); + expect(uuid.length).toBe(1); + }); + }); + + describe("Date queries", () => { + // Uses a test-specific schema with Date type + const DateTime = { + name: "Date", + properties: { name: "string", dateCompleted: "date" }, + }; + + let realm: Realm; + const path = "date.realm"; + + // Add, then delete Date objects for this test + beforeEach(async () => { + realm = await Realm.open({ + schema: [DateTime], + path, + }); + + realm.write(() => { + realm.create("Date", { + name: "now", + dateCompleted: new Date(), + }); + realm.create("Date", { + name: "past", + dateCompleted: new Date("December 17, 1985 03:24:00"), + }); + realm.create("Date", { + name: "withinYear", + dateCompleted: new Date("February 17, 2021 03:24:00"), + }); + }); + }); + + afterEach(() => { + realm.close(); + Realm.deleteFile({ path }); + }); + + // prettier-ignore + test("Date queries", () => { + const dates = realm.objects("Date"); + // :snippet-start: date-alt-representation + var lastYear = new Date(1577883184000); // Unix timestamp in ms + var thisYear = new Date("2021-01-01@17:30:15:0"); // DateTime in UTC + var today = new Date("April 01, 2021 03:24:00"); // Alternate DateTime format + // :snippet-end: + const dateParameterizedQuery = dates.filtered( + // :snippet-start: date-parameterized-query + // Find to-do items completed before today's date. + "dateCompleted < $0", today + + // :remove-start: + ); + + const dateAlt1 = dates.filtered( + // :remove-end: + // Find to-do items completed this year until today. + "dateCompleted > $0 AND dateCompleted < $1", thisYear, today + // :snippet-end: + ); + + expect(dateParameterizedQuery.length).toBe(2); + expect(dateAlt1.length).toBe(1); + }); + }); + + // prettier-ignore + test("Full-text search (FTS) query", () => { + const items = realm.objects(Item); + + const itemsWithWrite = items.filtered( + // :snippet-start: rql-fts + // Find items with 'write' in the name. + "name TEXT $0", "write" + + // :remove-start: + ); + + const itemsWithWriteNotTest = items.filtered( + // :remove-end: + // Use '-' to exclude: + // Find items with 'write' but not 'tests' in the name. + "name TEXT $0", "write -tests" + + // :remove-start: + ); + + const itemsStartingWithWri = items.filtered( + // :remove-end: + // Use '*' to match any suffix characters: + // Find items starting with 'wri-'. + "name TEXT $0", "wri*" + // :snippet-end: + ); + + expect(itemsWithWrite.length).toBe(2); + expect(itemsWithWriteNotTest.length).toBe(0); + expect(itemsStartingWithWri.length).toBe(2); + }); +}); diff --git a/examples/node/v12/__tests__/rql-data-models.test.js b/examples/node/v12/__tests__/rql-data-models.test.js new file mode 100644 index 0000000000..2a6500fb53 --- /dev/null +++ b/examples/node/v12/__tests__/rql-data-models.test.js @@ -0,0 +1,71 @@ +import Realm, { BSON } from "realm"; +import { Item, Project, Office, Address } from "./models/rql-data-models.ts"; + +describe("Test RQL Models", () => { + let realm; + const config = { schema: [Project, Item, Office, Address] }; + + beforeEach(async () => { + realm = await Realm.open(config); + }); + + afterEach(() => { + // After each test, delete the objects and close the realm + if (realm && !realm.isClosed) { + realm.write(() => { + realm.deleteAll(); + }); + realm.close(); + expect(realm.isClosed).toBe(true); + } + }); + + afterAll(() => { + Realm.deleteFile(config); + }); + + test("Can open realm with config", async () => { + expect(realm.isClosed).toBe(false); + }); + + test("Can create object of Item type", () => { + realm.write(() => { + realm.create(Item, { + _id: new BSON.ObjectId(), + name: "get coffee", + }); + }); + const coffeeItem = realm.objects(Item)[0]; + expect(coffeeItem._id instanceof BSON.ObjectId).toBe(true); + expect(coffeeItem.name).toBe("get coffee"); + expect(coffeeItem.isComplete).toBe(false); + }); + + test("Can create object of Project type", () => { + realm.write(() => { + const teaItem = realm.create(Item, { + _id: new BSON.ObjectId(), + name: "get tea", + }); + const officeAddress = realm.create(Office, { + name: "Austin", + address: { + name: "Main Branch", + street: "123 Main St", + zipcode: 10019, + }, + }); + realm.create(Project, { + _id: new BSON.ObjectId(), + name: "beverages", + items: [teaItem], + projectLocation: officeAddress, + }); + }); + const bevProject = realm.objects(Project)[0]; + expect(bevProject._id instanceof BSON.ObjectId).toBe(true); + expect(bevProject.name).toBe("beverages"); + expect(bevProject.items[0].name).toBe("get tea"); + expect(bevProject.projectLocation.name).toBe("Austin"); + }); +}); diff --git a/examples/node/v12/__tests__/rql-data-models.test.ts b/examples/node/v12/__tests__/rql-data-models.test.ts new file mode 100644 index 0000000000..046b94436b --- /dev/null +++ b/examples/node/v12/__tests__/rql-data-models.test.ts @@ -0,0 +1,81 @@ +import Realm, { BSON } from "realm"; +import { Item, Project, Office, Address } from "./models/rql-data-models.ts"; + +describe("Test RQL Models", () => { + let realm: Realm; + const config = { schema: [Project, Item, Office, Address] }; + + beforeEach(async () => { + realm = await Realm.open(config); + }); + + afterEach(() => { + if (realm && !realm.isClosed) { + realm.write(() => { + realm.deleteAll(); + }); + realm.close(); + expect(realm.isClosed).toBe(true); + } + }); + + afterAll(() => { + Realm.deleteFile(config); + }); + + test("Can open realm with config", async () => { + expect(realm.isClosed).toBe(false); + }); + + test("Can create object of Item type", () => { + const itemId = new BSON.ObjectId(); + realm.write(() => { + realm.create(Item, { + _id: itemId, + name: "get coffee", + }); + }); + const coffeeItem = realm.objects(Item)[0]; + expect(coffeeItem._id).toEqual(itemId); + expect(coffeeItem.name).toBe("get coffee"); + expect(coffeeItem.isComplete).toBe(false); + }); + + test("Can create object of Project type", () => { + const projectId = new BSON.ObjectId(); + realm.write(() => { + // Create the tea item + const teaItem = realm.create("Item", { + _id: new BSON.ObjectId(), + name: "get tea", + }); + + // Create the address object + const address = { + name: "Main Branch", + street: "123 Main St", + zipcode: 10019, + }; + + // Create the office object + const office = realm.create("Office", { + name: "Main Office", + address: address, + }); + // Create the project object + realm.create("Project", { + _id: projectId, + name: "beverages", + items: [teaItem], + projectLocation: office, + }); + }); + + const bevProject = realm.objects(Project)[0]; + expect(bevProject._id).toEqual(projectId); + expect(bevProject.name).toBe("beverages"); + expect(bevProject.items[0].name).toBe("get tea"); + expect(bevProject.projectLocation?.name).toBe("Main Office"); + expect(bevProject.projectLocation?.address.name).toBe("Main Branch"); + }); +}); diff --git a/examples/package-lock.json b/examples/package-lock.json new file mode 100644 index 0000000000..94f1164790 --- /dev/null +++ b/examples/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "examples", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst new file mode 100644 index 0000000000..ba78aca6c3 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst @@ -0,0 +1,18 @@ +.. code-block:: typescript + + var priorityNum = 5; + + // Find projects with average item `priority` above 5. + "items.@avg.priority > $0", priorityNum + + // Find projects where maximum `priority` of all items is 5. + "items.@max.priority < $0", priorityNum + + // Find projects where minimum `priority` of all items is 5. + "items.@min.priority > $0", priorityNum + + // Find projects with more than 5 items. + "items.@count > $0", 5 + + // Find projects with item `progressMinutes` greater than 100. + "items.@sum.progressMinutes > $0", 100 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst new file mode 100644 index 0000000000..24d0f66896 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "progressMinutes * priority == 90" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst new file mode 100644 index 0000000000..3388676d86 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst @@ -0,0 +1,9 @@ +.. code-block:: typescript + + // Find items that are referenced by multiple projects + "projects.@count > 1" + // Find items that are not referenced by any project + "@links.Project.items.@count == 0" + // Find items that belong to a project where the average item has + // been worked on for at least 5 minutes + "@links.Project.items.items.@avg.progressMinutes > 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atCount.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atCount.ts.rst new file mode 100644 index 0000000000..74bd83b430 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atCount.ts.rst @@ -0,0 +1,4 @@ +.. code-block:: typescript + + // Find items that are not referenced by another object of any type + "@links.@count == 0" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst new file mode 100644 index 0000000000..8346571665 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + // Find items that belong to a project with a quota + // less than 10 (using '@links'). + "@links.Project.items.quota < 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst new file mode 100644 index 0000000000..be0e56a7f9 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst @@ -0,0 +1,8 @@ +.. code-block:: typescript + + // Find items where ANY project that references the item + // has a quota greater than 10. + "ANY @links.Project.items.quota > 10" + // Find items where ALL projects that reference the item + // have a quota less than 5. + "ALL @links.Project.items.quota < 5" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst new file mode 100644 index 0000000000..7269485ca6 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + // Find items that belong to a project with a quota greater than 10 + // (using 'LinkingObjects'). + "projects.quota > 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst new file mode 100644 index 0000000000..5e23fdbb10 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + // Find items with a `priority` greater than 3. + "2 * priority > 6" // `priority > 3` + "priority >= 2 * (2 - 1) + 2" // `priority >= 4` diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst new file mode 100644 index 0000000000..34128a6378 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst @@ -0,0 +1,16 @@ +.. code-block:: typescript + + // Compare `priority` values against a threshold value. + "priority > $0", 5 + + // Compare `progressMinutes` values against a threshold value. + "progressMinutes > $0", 120 + + // Compare `assignee` values to `null` value. + "assignee == $0", null + + // Compare `priority` values against an inclusive range of values. + "priority BETWEEN { $0 , $1 }", 1, 5 + + // Compare `progressMinutes` values against any of the listed values. + "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst new file mode 100644 index 0000000000..9cfacf588a --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + var lastYear = new Date(1577883184000); // Unix timestamp in ms + var thisYear = new Date("2021-01-01@17:30:15:0"); // DateTime in UTC + var today = new Date("April 01, 2021 03:24:00"); // Alternate DateTime format diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst new file mode 100644 index 0000000000..fd06d334ce --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst @@ -0,0 +1,7 @@ +.. code-block:: typescript + + // Find to-do items completed before today's date. + "dateCompleted < $0", today + + // Find to-do items completed this year until today. + "dateCompleted > $0 AND dateCompleted < $1", thisYear, today diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst new file mode 100644 index 0000000000..db769f001a --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "projectLocation.address.zipcode == 10019" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst new file mode 100644 index 0000000000..1f883a4627 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst @@ -0,0 +1,25 @@ +.. code-block:: typescript + + // Find `comments` dictionary properties with key 'status'. + "comments.@keys == $0", "status" + + // Find `comments` dictionary properties with key 'status' + // and value 'On track'. + "comments['status'] == $0", "On track" + // Find `comments` dictionary properties with + // more than one key-value pair. + "comments.@count > $0", 1 + + // Find `comments` dictionary properties where ANY + // values are of type 'string`. + "ANY comments.@type == 'string'" + "comments.@type == 'string'" // (Equivalent - ANY is implied.) + + // Find `comments` dictionary properties where ALL + // values are of type 'int'. + "ALL comments.@type == 'int'" + + // Find `comments` dictionary properties where NO + // values are of type 'int'. + "NONE comments.@type == 'int'" + diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst new file mode 100644 index 0000000000..290b29341e --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "oid(631a072f75120729dc9223d9) IN items._id" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst new file mode 100644 index 0000000000..0641020373 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst @@ -0,0 +1,8 @@ +.. code-block:: typescript + + const ids = [ + new BSON.ObjectId("631a072f75120729dc9223d9"), + new BSON.ObjectId("631a0737c98f89f5b81cd24d"), + new BSON.ObjectId("631a073c833a34ade21db2b2"), + ]; + const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst new file mode 100644 index 0000000000..e79c902584 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "priority IN {0, 1, 2}" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst new file mode 100644 index 0000000000..f6a05abb5f --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst @@ -0,0 +1,7 @@ +.. code-block:: typescript + + // Find all items assigned to Ali AND marked completed. + "assignee == $0 AND isComplete == $1", "Ali", true + + // Find all items assigned to Alex OR to Ali. + "assignee == $0 OR assignee == $1", "Alex", "Ali" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst new file mode 100644 index 0000000000..6f376e9336 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst @@ -0,0 +1,4 @@ +.. code-block:: typescript + + // comparison to language null pointer + "assignee == $0", null diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst new file mode 100644 index 0000000000..38ea382f9b --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "assignee == nil" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst new file mode 100644 index 0000000000..1b7ee896b1 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "_id == $0", oidValue diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst new file mode 100644 index 0000000000..a7909effbe --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "_id == oid(6001c033600510df3bbfd864)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst new file mode 100644 index 0000000000..e1d7564bc5 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst @@ -0,0 +1,8 @@ +.. code-block:: typescript + + // Include one parameter with `$0`. + "progressMinutes > 1 AND assignee == $0", "Ali" + + // Include multiple parameters using ascending integers, + // starting at`$0`. + "progressMinutes > $0 AND assignee == $1", 1, "Alex" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst new file mode 100644 index 0000000000..3b9ac369fa --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + const expression = "priority == 1"; diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst new file mode 100644 index 0000000000..b861e87002 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst @@ -0,0 +1,12 @@ +.. code-block:: typescript + + // Find items with 'write' in the name. + "name TEXT $0", "write" + + // Use '-' to exclude: + // Find items with 'write' but not 'tests' in the name. + "name TEXT $0", "write -tests" + + // Use '*' to match any suffix characters: + // Find items starting with 'wri-'. + "name TEXT $0", "wri*" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst new file mode 100644 index 0000000000..e51d4723e7 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "progressMinutes > 1 AND assignee == 'Ali'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst new file mode 100644 index 0000000000..a2667eece5 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst @@ -0,0 +1,17 @@ +.. code-block:: typescript + + // Find projects with no complete items. + "NONE items.isComplete == $0", true + + // Find projects that contain an item with priority 10. + "ANY items.priority == $0", 10 + + // Find projects that only contain completed items. + "ALL items.isComplete == $0", true + + // Find projects with at least one item assigned to + // either Alex or Ali. + "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" + + // Projects with no items assigned to either Alex or Ali. + "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst new file mode 100644 index 0000000000..2dcfe9e8fd --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + const items = realm.objects(Item); + // Get all items where 'priority' property is 7 or more. + const importantItems = items.filtered("priority >= $0", 7); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst new file mode 100644 index 0000000000..7ee32e3146 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst new file mode 100644 index 0000000000..8effdea009 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst @@ -0,0 +1,9 @@ +.. code-block:: typescript + + // Find projects whose name starts with the letter 'e' + // (case-insensitive). + "name BEGINSWITH[c] $0", "e" + + // Find projects whose name contains the letters 'ie' + // (case-sensitive). + "name CONTAINS $0", "ie" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst new file mode 100644 index 0000000000..51371a79fa --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + // Find projects where the number of completed to-do items + // is greater than or equal to the project's `quota` property. + "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst new file mode 100644 index 0000000000..9228876e1c --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst @@ -0,0 +1,4 @@ +.. code-block:: typescript + + // Find projects with incomplete to-do items assigned to Alex. + "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst new file mode 100644 index 0000000000..90a837faa8 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + "mixedType.@type == 'string'" + + "mixedType.@type == 'bool'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst new file mode 100644 index 0000000000..1141952739 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst @@ -0,0 +1,3 @@ +.. code-block:: typescript + + "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" diff --git a/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst b/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst new file mode 100644 index 0000000000..57dfa8ba30 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst @@ -0,0 +1,49 @@ +.. code-block:: typescript + + export class Item extends Realm.Object { + _id!: BSON.ObjectId; + name!: string; + isComplete!: boolean; + assignee?: string; + priority!: number; + progressMinutes?: number; + + static schema: ObjectSchema = { + name: "Item", + properties: { + _id: "objectId", + name: { type: "string", indexed: "full-text" }, + isComplete: { type: "bool", default: false }, + assignee: "string?", + priority: { type: "int", default: 0 }, + progressMinutes: { type: "int", default: 0 }, + projects: { + type: "linkingObjects", + objectType: "Project", + property: "items", + }, + }, + primaryKey: "_id", + }; + } + export class Project extends Realm.Object { + _id!: BSON.ObjectId; + name!: string; + items!: Realm.List; + quota?: number; + comments?: Realm.Dictionary; + projectLocation?: Office; + + static schema: ObjectSchema = { + name: "Project", + properties: { + _id: "objectId", + name: "string", + items: "Item[]", + quota: "int?", + comments: "string?{}", + projectLocation: "Office?", + }, + primaryKey: "_id", + }; + } From 78d4535d21980c678b9f767e8fbb942c7c410d29 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 21 May 2024 15:03:18 -0400 Subject: [PATCH 05/12] RQL page updates --- .../__tests__/realm-query-language.test.ts | 64 +- ...t.snippet.arithmetic-obj-properties.ts.rst | 3 - ...nippet.nil-type-parameterized-query.ts.rst | 4 - .../query-engines/realm-query-language.txt | 900 +++--------------- 4 files changed, 164 insertions(+), 807 deletions(-) delete mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst delete mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts index fc7fa248d6..97dccebb9f 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.ts +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -201,12 +201,22 @@ describe("Realm Query Language Reference", () => { test("Dot notation", () => { const address = realm.objects(Project); - const nestedMatch = address.filtered( + const nestedItem = address.filtered( + // :snippet-start: dot-notation + // Find projects whose `items` list property contains + // an Item object with a specific name. + "items[0].name == 'Approve project plan'" + // :snippet-end: + ); + const nestedZipcode = address.filtered( // :snippet-start: deep-dot-notation + // Find projects whose `projectLocation` property contains + // an embedded Address object with a specific zip code. "projectLocation.address.zipcode == 10019" // :snippet-end: ); - expect(nestedMatch.length).toBe(3); + expect(nestedItem.length).toBe(2); + expect(nestedZipcode.length).toBe(3); }); }); @@ -222,15 +232,6 @@ describe("Realm Query Language Reference", () => { ); expect(highPriorityItems.length).toBe(5); - const longRunningItems = items.filtered( - // :remove-end: - - // Compare `progressMinutes` values against a threshold value. - "progressMinutes > $0", 120 - // :remove-start: - ); - expect(longRunningItems.length).toBe(1); - const unassignedItems = items.filtered( // :remove-end: @@ -250,13 +251,12 @@ describe("Realm Query Language Reference", () => { expect(progressMinutesRange.length).toBe(2); const progressMinutesIn = items.filtered( - // :remove-end: + // :remove-end: // Compare `progressMinutes` values against any of the listed values. "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 // :snippet-end: ); - expect(progressMinutesIn.length).toBe(2); }); // prettier-ignore @@ -284,14 +284,14 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const basicMath = items.filtered( // :snippet-start: basic-arithmetic - // Find items with a `priority` greater than 3. - "2 * priority > 6" // `priority > 3` + // Evaluate against an item's `priority` property value: + "2 * priority > 6" // resolves to `priority > 3` // :remove-start: ); const lessBasicMath = items.filtered( // :remove-end: - "priority >= 2 * (2 - 1) + 2" // `priority >= 4` - // :snippet-end: + "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` + // :remove-start: ); expect(basicMath.length).toBe(6); expect(lessBasicMath.length).toBe(6); @@ -300,7 +300,9 @@ describe("Realm Query Language Reference", () => { test("Arithmetic with object properties", () => { const items = realm.objects(Item); const mathWithObjProps = items.filtered( - // :snippet-start: arithmetic-obj-properties + // :remove-end: + + // Evaluate against multiple object property values: "progressMinutes * priority == 90" // :snippet-end: ); @@ -466,6 +468,7 @@ describe("Realm Query Language Reference", () => { test("Sort, distinct, and limit results", () => { const items = realm.objects(Item); + const projects = realm.objects(Project); const sortedUniqueAliItems = items.filtered( // :snippet-start: sort-distinct-limit @@ -474,6 +477,24 @@ describe("Realm Query Language Reference", () => { ); expect(sortedUniqueAliItems.length).toBe(1); + const query = + // :snippet-start: sort-distinct-limit-order-matters + "SORT(priority DESC) LIMIT(2) DISTINCT(name)"; + // Returns 2 items with the highest priority + // :remove-start: + const orderMatters = items.filtered( + "isComplete != true SORT(priority DESC) LIMIT(2) DISTINCT(name)" + ); + expect(orderMatters.length).toBe(2); + const query2 = + // :remove-end: + "isComplete != true DISTINCT(name) SORT(priority DESC) LIMIT(2)"; + // Returns the first 2 uniquely named items with the highest priority + // :snippet-end: + const limitFirst = items.filtered( + "isComplete != true DISTINCT(name) SORT(priority DESC) LIMIT(2)" + ); + console.log(limitFirst.toJSON()); }); test("Subquery queries", () => { @@ -711,12 +732,13 @@ describe("Realm Query Language Reference", () => { const res = items.filtered( // :snippet-start: nil-type "assignee == nil" - // :snippet-end: + // :remove-start: ); // prettier-ignore const res2 = realm.objects(Item).filtered( - // :snippet-start: nil-type-parameterized-query - // comparison to language null pointer + // :remove-end: + + // 'null' maps to the SDK language's null pointer "assignee == $0", null // :snippet-end: ); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst deleted file mode 100644 index 24d0f66896..0000000000 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.arithmetic-obj-properties.ts.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. code-block:: typescript - - "progressMinutes * priority == 90" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst deleted file mode 100644 index 6f376e9336..0000000000 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type-parameterized-query.ts.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. code-block:: typescript - - // comparison to language null pointer - "assignee == $0", null diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index a7c2cdd014..3eb1f675e5 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -1,23 +1,30 @@ .. _realm-query-language: .. _rql: -==================== -Realm Query Language -==================== +========================== +Realm Query Language (RQL) +========================== .. meta:: - :description: Learn how to use Realm Query Language (RQL) to retrieve objects from the database. - -.. facet:: - :name: genre + :description: Use Realm Query Language (RQL) to retrieve objects from the database. + :keywords: Realm, Flutter SDK, Kotlin SDK, Java SDK, Node.js SDK, code example, filter, search + +.. facet:: + :name: genre :values: reference +.. facet:: + :name: programming_language + :values: cpp, csharp, dart, java, javascript/typescript, kotlin + .. contents:: On this page :local: :backlinks: none :depth: 3 :class: singlecol +.. tabs-selector:: drivers + Realm Query Language (RQL) is a string-based query language to constrain searches when retrieving objects from a realm. SDK-specific methods pass queries to the Realm query engine, which retrieves matching objects from the realm. @@ -42,7 +49,7 @@ documentation: - :ref:`Fluent Interface (Java SDK) ` - :ref:`LINQ (.NET SDK) ` - :ref:`Type-Safe and NSPredicate Queries (Swift SDK) ` - + .. note:: Swift SDK does not support Realm Query Language The Swift SDK does not support querying with Realm Query Language. @@ -67,250 +74,78 @@ The two Realm object types are ``Project`` and ``Item``. See the schema for these two classes, ``Project`` and ``Item``, below: -.. tabs:: - - .. tab:: Java SDK - :tabid: java - - .. tabs-realm-languages:: - - .. tab:: - :tabid: java - - .. code-block:: java - - public class Item extends RealmObject { - ObjectId id = new ObjectId(); - String name; - Boolean isComplete = false; - String assignee; - Integer priority = 0; - Integer progressMinutes = 0; - @LinkingObjects("items") - final RealmResults projects = null; - } - public class Project extends RealmObject { - ObjectId id = new ObjectId(); - String name; - RealmList items; - Integer quota = null; - } - - .. tab:: - :tabid: kotlin - - .. code-block:: kotlin - - open class Item(): RealmObject() { - var id: ObjectId = new ObjectId() - @FullText - lateinit var name: String - var isComplete: Boolean = false - var assignee: String? = null - var priority: Int = 0 - var progressMinutes: Int = 0 - } - - open class Project(): RealmObject() { - var id: ObjectId = new ObjectId() - lateinit var name: String - lateinit var items: RealmList - var quota: Int? = null - } - - .. tab:: .NET SDK - :tabid: dotnet - - .. literalinclude:: /examples/generated/dotnet/RqlSchemaExamples.snippet.rql-schema-examples.cs - :language: csharp - - .. tab:: Node.js SDK - :tabid: node - - .. literalinclude:: /examples/generated/node/rql-data-models.snippet.rql-data-models.js - :language: javascript +.. include:: /includes/sdk-examples/crud/query/rql/rql-example-data-model.rst - .. tab:: React Native SDK - :tabid: react-native - .. literalinclude:: /examples/generated/node/rql-data-models.snippet.rql-data-models.js - :language: javascript +Query Syntax +------------ - .. tab:: Kotlin SDK - :tabid: kotlin - .. literalinclude:: /examples/generated/kotlin/RQLTest.snippet.rql-schema-example.kt - :language: kotlin - .. tab:: Flutter SDK - :tabid: Flutter +Dot Notation +~~~~~~~~~~~~ - .. literalinclude:: /examples/generated/flutter/task_project_models_test.snippet.task-project-models.dart - :language: dart +You can use **dot notation** to refer to child properties of an object, including the properties of embedded objects and relationships: -Expressions ------------ +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst -Filters consist of **expressions** in a predicate. An expression consists of -one of the following: +You can also chain dot notations for nested properties. +For example, each Project has a ``projectLocation`` property that +refers to an Office object, which itself contains an embedded object +property ``address``. You can chain dot notations to query the deeply nested +``zipcode`` property of an embedded address: -- The name of a property of the object currently being evaluated. -- An operator and up to two argument expression(s). For example, in the - expression ``A + B``, the entirety of ``A + B`` is an expression, but ``A`` - and ``B`` are also argument expressions to the operator ``+``. -- A value, such as a string (``'hello'``) or a number (``5``). +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.predicate.js - :language: javascript +.. TODO: add as part of collections-in-mixed epic +Bracket Notation +~~~~~~~~~~~~~~~~ .. _rql-parameterized-queries: -Parameterized Queries ---------------------- - -Create parameterized queries to interpolate variables into prepared -Realm Query Language statements. The syntax for interpolated variables is -``$``, starting at ``0``. Pass the positional arguments as -additional arguments to Realm SDK methods that use Realm Query Language. - -Include just one parameter with ``$0``. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.predicate.js - :language: js - -Include multiple parameters with ascending integers starting at ``$0``. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.multiple-predicate.js - :language: js +Parameterized vs. Serialized Queries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Query Formats -~~~~~~~~~~~~~ +You can format queries in two ways: -The following table shows how a query should be formatted when serialized and -parameterized for the following data types: +- **Serialized queries** pass values directly in the expression. -.. list-table:: - :header-rows: 1 - :widths: 15 25 25 35 - - * - Type - - Parameterized Example - - Serialized Example - - Note - - * - Boolean - - "setting == $0", false - - "setting == false" - - ``true`` or ``false`` values. - - * - :ref:`String ` - - "name == $0", "George" - - "name == 'George'" - - Applies to ``string`` and ``char`` data type. - - * - :ref:`Number ` - - "age > $0", 5.50 - - "age > 5.50" - - Applies to ``int``, ``short``, ``long``, ``double``, ``Decimal128``, and ``float`` data types. - - * - :ref:`Date ` - - "date < $0", dateObject - - "date < 2021-02-20\@17:30:15:0" - - For parameterized date queries, you must pass in a date object. - For serialized date queries, you can represented the date in the following formats: - - - As an explicit date and time- YYYY-MM-DD\@HH:mm:ss:nn - (year-month-day@hours:minutes:seconds:nanoseconds) - - As a ``datetime`` relative to the :wikipedia:`Unix epoch `- Ts:n - (T, designates the start of the time; ``s``, seconds; ``n``, nanoseconds) - - Parameterized ``Date`` object - - * - :ref:`ObjectID ` - - "_id == $0", oidValue - - "_id == oid(507f1f77bcf86cd799439011)" - - For parameterized ObjectId queries, you must pass in an ObjectId. - For serialized ObjectId queries, the string representation is ``oid()``. - - * - :ref:`UUID ` - - "id == $0", uuidValue - - "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" - - For parameterized UUID queries, you must pass in a UUID. - For serialized UUID queries, the string representation is ``uuid()``. - - * - Binary - - "value == $0", "binary" - - "value == 'binary'" - - For ASCII characters, RQL serializes the binary value like a string, - with quotes. For non-printable characters, - RQL serializes the binary to a base 64 value. - - * - :ref:`List ` - - "ANY items.name == {$0, $1}", "milk", "bread" - - "ANY items.name == {'milk', 'bread'}" - - Applies for list, collections, and sets. A parameterized value should be used - for each member of the list. - - * - RealmObject - - "ANY items == $0", obj("Item", oid(6489f036f7bd0546377303ab)) - - "ANY items == obj('Item', oid(6489f036f7bd0546377303ab))" - - To pass in a RealmObject, you need the class and primary key of the object. - -.. _rql-dot-notation: - -Dot Notation ------------- +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst -When referring to an object property, you can use **dot notation** to refer -to child properties of that object. You can even refer to the properties of -embedded objects and relationships with dot notation. +- **Parameterized queries** pass interpolated variables as additional + arguments. The syntax for interpolated variables is + ``$``, starting at ``0`` and incrementing for each additional variable. -For example, consider a query on an object with a ``workplace`` property that -refers to a Workplace object. The Workplace object has an embedded object -property, ``address``. You can chain dot notations to refer to the zipcode -property of that address: +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.deep-dot-notation.js - :language: js +Supported Types +~~~~~~~~~~~~~~~ .. _rql-nil-type: Nil Type --------- +```````` -Realm Query Language include the ``nil`` type to represent a null pointer. +Realm Query Language includes the ``nil`` type to represent a null pointer. You can either reference ``nil`` directly in your queries or with a parameterized query. If you're using a parameterized query, each SDK maps its respective null pointer to ``nil``. -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.nil-type.js - :language: js - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.nil-type-parameterized-query.js - :language: js +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst .. _rql-operators: -.. _rql-comparison-operators: - -Comparison Operators --------------------- -The most straightforward operation in a search is to compare -values. +Operators +--------- -.. important:: Types Must Match - - The type on both sides of the operator must be equivalent. For - example, comparing an ObjectId with string will result in a precondition - failure with a message like: +.. _rql-comparison-operators: - .. code-block:: - :copyable: false +Comparison Operators +~~~~~~~~~~~~~~~~~~~~ - "Expected object of type object id for property 'id' on object of type - 'User', but received: 11223344556677889900aabb (Invalid value)" +Use comparison operators to compare values of matching data types. - You can compare any numeric type with any other numeric type, - including decimal, float, and Decimal128. +.. TODO: link or mention how ANY works (noted as equivalent to IN in this table) .. list-table:: :header-rows: 1 @@ -319,7 +154,7 @@ values. * - Operator - Description - * - ``BETWEEN {number1, number2}`` + * - ``BETWEEN {N1, N2}`` - Evaluates to ``true`` if the left-hand numerical or date expression is between or equal to the right-hand range. For dates, this evaluates to ``true`` if the left-hand date is within the right-hand date range. @@ -361,28 +196,32 @@ values. - Evaluates to ``true`` if the left-hand expression is not equal to the right-hand expression. -.. example:: - The following example uses Realm Query Language's comparison operators to: +The following example uses comparison operators to find to-do items whose +property values match certain criteria: - - Find high priority to-do items by comparing the value of the ``priority`` - property value with a threshold number, above which priority can be considered high. - - Find long-running to-do items by seeing if the ``progressMinutes`` property - is at or above a certain value. - - Find unassigned to-do items by finding items where the ``assignee`` property - is equal to ``null``. - - Find to-do items within a certain time range by finding items where the - ``progressMinutes`` property is between two numbers. - - Find to-do items with a certain amount of ``progressMinutes`` from the - given list. +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst + +.. important:: Types Must Match + + The type on both sides of the operator must be equivalent. For + example, comparing an ObjectId with string will result in a precondition + failure with a message like: + + .. code-block:: + :copyable: false + + "Expected object of type object id for property 'id' on object of type + 'User', but received: 11223344556677889900aabb (Invalid value)" + + You can compare any numeric type with any other numeric type, + including decimal, float, and Decimal128. - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.comparison-operators.js - :language: javascript .. _rql-logical-operators: Logical Operators ------------------ +~~~~~~~~~~~~~~~~~ Make compound predicates using logical operators. @@ -405,145 +244,17 @@ Make compound predicates using logical operators. | ``||`` - Evaluates to ``true`` if either expression returns ``true``. -.. example:: - - We can use the query language's logical operators to find - all of Ali's completed to-do items. That is, we find all items - where the ``assignee`` property value is equal to 'Ali' AND - the ``isComplete`` property value is ``true``: - - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.logical-operators.js - :language: javascript - -.. _rql-string-operators: - -String Operators ----------------- - -Compare string values using these string operators. -Regex-like wildcards allow more flexibility in search. - -.. note:: - - You can use the following modifiers with the string operators: - - - ``[c]`` for case insensitivity. - - .. code-block:: javascript - - "name CONTAINS[c] $0", 'a' - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Operator - - Description - - * - | ``BEGINSWITH`` - - Evaluates to ``true`` if the left-hand string expression begins with - the right-hand string expression. This is similar to ``contains``, - but only matches if the right-hand string expression is found - at the beginning of the left-hand string expression. - - * - | ``CONTAINS`` - - Evaluates to ``true`` if the right-hand string expression - is found anywhere in the left-hand string expression. - - * - | ``ENDSWITH`` - - Evaluates to ``true`` if the left-hand string expression ends - with the right-hand string expression. This is similar to ``contains``, - but only matches if the left-hand string expression is found - at the very end of the right-hand string expression. - - * - | ``LIKE`` - - Evaluates to ``true`` if the left-hand string expression - matches the right-hand string wildcard string - expression. A wildcard string expression is a string - that uses normal characters with two special wildcard - characters: - - - The ``*`` wildcard matches zero or more of any character - - The ``?`` wildcard matches any character. - - For example, the wildcard string "d?g" matches "dog", - "dig", and "dug", but not "ding", "dg", or "a dog". - - * - | ``==``, ``=`` - - Evaluates to ``true`` if the left-hand string is lexicographically equal - to the right-hand string. - - * - | ``!=``, ``<>`` - - Evaluates to ``true`` if the left-hand string is not lexicographically - equal to the right-hand string. - -.. example:: - - We use the query engine's string operators to find: - - - Projects with a name starting with the letter 'e' - - Projects with names that contain 'ie' +The following example uses logical operators to combine multiple predicates: - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.string-operators.js - :language: javascript - -.. _rql-objectid-uuid-operators: - -ObjectId and UUID Operators ---------------------------- - -Query :manual:`BSON ObjectIds ` and -:manual:`UUIDs `. -These data types are often used as primary keys. - -To query with ObjectIds, use a parameterized query. Pass the ObjectId or UUID -you're querying against as the argument. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.oid-literal.js - :language: js - -You can also put a string representation of the ObjectId you're evaluating -in ``oid()``. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.oid.js - :language: js - -To query with UUIDs, put a string representation of the UUID you're evaluating -in ``uuid()``. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.uuid.js - :language: js - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Operator - - Description - - * - | ``==``, ``=`` - - Evaluates to ``true`` if the left-hand value is equal - to the right-hand value. - - * - | ``!=``, ``<>`` - - Evaluates to ``true`` if the left-hand value is not equal - to the right-hand value. +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst .. _rql-arithmetic-operators: Arithmetic Operators --------------------- - -Perform basic arithmetic in one side of a RQL expression when evaluating -numeric data types. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.basic-arithmetic.js - :language: js - -You can also use multiple object properties together in a mathematic operation. +~~~~~~~~~~~~~~~~~~~~ -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.arithmetic-obj-properties.js - :language: js +Use arithmetic operators to perform basic arithmetic in an expression when +evaluating numeric data types, including object properties. .. list-table:: :header-rows: 1 @@ -563,112 +274,17 @@ You can also use multiple object properties together in a mathematic operation. * - | ``()`` - Group expressions together. -.. _rql-type-operator: +The following example uses arithmetic operators on Item object properties containing numeric values: -Type Operator -------------- - -Check the type of a property using the ``@type`` operator. -You can only use the type operator with mixed types and dictionaries. - -Evaluate the property against a string representation of the data type name. -Refer to SDK documentation on the mapping from the SDK language's data types -to Realm data types. - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Operator - - Description - - * - ``@type`` - - Check if type of a property is the property name as a string. - Use ``==`` and ``!=`` to compare equality. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.type-operator.js - :language: js - -.. _rql-dictionary-operators: - -Dictionary Operators --------------------- - -Compare dictionary values using these dictionary operators. - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Operator - - Description - - * - ``@values`` - - Returns objects that have the value specified in the right-hand expression. - - * - ``@keys`` - - Returns objects that have the key specified in the right-hand expression. - - * - ``@size``, ``@count`` - - The number of elements in a dictionary. - - * - ``Dictionary['key']`` - - Access the value at a key of a dictionary. - - * - ``ALL | ANY | NONE .@type`` - - Checks if the dictionary contains properties of certain type. - -You can also use dictionary operators in combination with -:ref:`comparison operators ` to filter objects -based on dictionary keys and values. The following examples show some ways -to use dictionary operators with comparison operators. All examples query -a collection of Realm objects with a dictionary property named ``dict``. - -.. example:: - - The following examples use various dictionary operators. - - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.dictionary-operators.js - :language: js - -.. _rql-date-operators: - -Date Operators --------------- - -Query date types in a realm. - -Generally, you should use a parameterized query to pass a date data type -from the SDK language you are using to a query. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.date-parameterized-query.js - :language: js - -You can also specify dates in the following two ways: - -- As a specific date (in UTC)- ``YYYY-MM-DD@HH:mm:ss:nnnnnnnnnn`` (year-month-day@hours:minutes:seconds:nanoseconds), UTC. - You can also use ``T`` instead of ``@`` to separate the date from the time. -- As a time in seconds since the :wikipedia:`Unix epoch `- ``Ts:n``, where ``T`` designates the start of the time, - ``s`` is the number of seconds, and ``n`` is the number of nanoseconds. - -Date supports :ref:`comparison operators `. - -.. example:: - - The following example shows how to use a parameterized query with - a date object: - - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.date-alt-representation.js - :language: js +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst .. _rql-aggregate-operators: Aggregate Operators -------------------- +~~~~~~~~~~~~~~~~~~~ -Apply an aggregate operator to a collection property of a Realm -object. Aggregate operators traverse a collection and reduce it to a -single value. +Aggregate operators traverse a collection and reduce it to a single value. +You can use aggregate operators on collection properties, such as a list, or on .. list-table:: :header-rows: 1 @@ -697,334 +313,42 @@ single value. - Evaluates to the sum of a given numerical property across a collection, excluding ``null`` values. -.. example:: - - These examples all query for projects containing to-do items that meet - this criteria: - - - Projects with average item priority above 5. - - Projects with an item whose priority is less than 5. - - Projects with an item whose priority is greater than 5. - - Projects with more than 5 items. - - Projects with long-running items. - - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.aggregate-operators.js - :language: javascript - -.. _rql-collection-operators: - -Collection Operators --------------------- - -A **collection operator** lets you query list properties within a collection of objects. -Collection operators filter a collection by applying a predicate -to every element of a given list property of the object. -If the predicate returns true, the object is included in the output collection. - -.. list-table:: - :header-rows: 1 - :widths: 30 70 - - * - Operator - - Description - - * - ``ALL`` - - Returns objects where the predicate evaluates to ``true`` for all objects - in the collection. - - * - ``ANY``, ``SOME`` - - Returns objects where the predicate evaluates to ``true`` for any objects - in the collection. - - * - ``NONE`` - - Returns objects where the predicate evaluates to false for all objects - in the collection. - -.. example:: - - This example uses collection operators to find projects that contain to-do items - matching certain criteria: - - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.set-operators.js - :language: js - -.. _rql-list-queries: - -List Comparisons ----------------- - -You can use :ref:`comparison operators ` and -:ref:`collection operators ` to filter based -on lists of data. - -You can compare any type of valid list. This includes: - -- collections of Realm objects, which let you filter against other data - in the realm. - - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.list-comparisons-collection.js - :language: js - -- lists defined directly in the query, which let you filter against - static data. You define static lists as a comma-separated list of - literal values enclosed in opening (``{``) and closing (``}``) braces. - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.list-comparisons-static.js - :language: js +The following example uses aggregate operators to find project whose ``items`` +collection property meets certain criteria: -- native list objects passed in a :ref:`parameterized expression - `, which let you pass application data - directly to your queries. +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.list-comparisons-parameterized.js - :language: js - -If you do not define a collection operator, a list expression defaults -to the ``ANY`` operator. - -.. example:: - - These two list queries are equivalent: - - - ``age == ANY {18, 21}`` - - ``age == {18, 21}`` - - Both of these queries return objects with an age property equal to - either 18 or 21. You could also do the opposite by returning objects - only if the age is not equal to either 18 or 21: - - - ``age == NONE {18, 21}`` - -The following table includes examples that illustrate how collection -operators interact with lists and comparison operators: - -.. list-table:: - :widths: 45 10 45 - - * - Expression - - Match? - - Reason - - * - ``ANY {1, 2, 3} > ALL {1, 2}`` - - true - - A value on the left (3) is greater than some value on the right (both 1 and 2) - - * - ``ANY {1, 2, 3} == NONE {1, 2}`` - - true - - 3 does not match either of 1 or 2 - - * - ``ANY {4, 8} == ANY {5, 9, 11}`` - - false - - Neither 4 nor 8 matches any value on the right (5, 9 or 11) - - * - ``ANY {1, 2, 7} <= NONE {1, 2}`` - - true - - A value on the left (7) is not less than or equal to both 1 and 2 - - * - ``ALL {1, 2} IN ANY {1, 2, 3}`` - - true - - Every value on the left (1 and 2) is equal to 1, 2 or 3 - - * - ``ALL {3, 1, 4, 3} == NONE {1, 2}`` - - false - - 1 matches a value in the NONE list (1 or 2) - - * - ``ALL {} in ALL {1, 2}`` - - true - - An empty list matches all lists - - * - ``NONE {1, 2, 3, 12} > ALL {5, 9, 11}`` - - false - - 12 is bigger than all values on the right (5, 9, and 11) - - * - ``NONE {4, 8} > ALL {5, 9, 11}`` - - true - - 4 and 8 are both less than some value on the right (5, 9, or 11) - - * - ``NONE {0, 1} < NONE {1, 2}`` - - true - - 0 and 1 are both less than none of 1 and 2 - -.. _rql-fts: - -Full Text Search ----------------- - -You can use RQL to query on properties that have a full-text search (FTS) -annotation. FTS supports boolean match word searches, rather than searches for relevance. -For information on enabling FTS on a property, refer to :ref:`sdks-fts-property`. - -To query these properties, use the ``TEXT`` predicate in your query. - -You can search for entire words or phrases, or limit your results with the following characters: - -- Exclude results for a word by placing the ``-`` character in front of the word. -- Specify prefixes by placing the ``*`` character at the end of a prefix. Suffix - searching is not currently supported. - -In the following example, we query the ``Item.name`` property: - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.test.snippet.rql-fts.js - :language: js - -Full-Text Search Tokenizer Details -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Full-Text Search (FTS) indexes support: - -- Tokens are diacritics- and case-insensitive. -- Tokens can only consist of characters from ASCII and the Latin-1 supplement (western languages). - All other characters are considered whitespace. -- Words split by a hyphen (-) are split into two tokens. For example, ``full-text`` - splits into ``full`` and ``text``. - -.. _rql-geospatial: - -Geospatial Queries ------------------- - -You can query against geospatial data using the ``geoWithin`` operator. -The ``geoWithin`` operator takes the latitude/longitude pair in a custom -embedded object's ``coordinates`` property and a geospatial shape. The -operator checks whether the ``cordinates`` point is contained within the -geospatial shape. - -The following geospatial shapes are supported for querying: - -- ``GeoCircle`` -- ``GeoBox`` -- ``GeoPolygon`` - -To query geospatial data: - -1. Create an object with a property containing the embedded geospatial data. -2. Define the geospatial shape to set the boundary for the query. -3. Query using the ``geoWithin`` RQL operator. - -In the following query, we are checking that the coordinates of the embeddeded -``location`` property are contained within the ``GeoCircle`` shape, ``smallCircle``: - -.. literalinclude:: /examples/generated/node/v12/geospatial.test.snippet.rql-geospatial.js - :language: js - -For more information on defining geospatial shapes and objects with embedded -geospatial data, refer to :ref:`sdks-define-geospatial-object`. - -.. _rql-backlinks: - -Backlink Queries ----------------- - -A backlink is an inverse relationship link that lets you look up objects -that reference another object. Backlinks use the to-one and to-many -relationships defined in your object schemas but reverse the direction. -Every relationship that you define in your schema implicitly has a -corresponding backlink. - -You can access backlinks in queries using the -``@links..`` syntax, where ```` -and ```` refer to a specific property on an object type -that references the queried object type. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.backlinks-atLinks.js - :language: js - -You can also define a ``linkingObjects`` property to explicitly include -the backlink in your data model. This lets you reference the backlink -through an assigned property name using standard :ref:`dot notation -`. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.backlinks-linkingObjects.js - :language: js - -The result of a backlink is treated like a collection and supports -:ref:`collection operators `. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.backlinks-collection-operators.js - :language: js - -You can use :ref:`aggregate operators ` on the backlink collection. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.backlinks-aggregate-operators.js - :language: js - -You can query the count of all relationships that point to an object by -using the ``@count`` operator directly on ``@links``. - -.. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.backlinks-atCount.js - :language: js - -.. _rql-subqueries: - -Subqueries ----------- - -Iterate through list properties with another query using the -``SUBQUERY()`` predicate function. - -Subqueries are useful for the following scenarios: - -- Matching each object in a list property on multiple conditions -- Counting the number of objects that match a subquery - - -``SUBQUERY()`` has the following structure: - -.. code-block:: js - - SUBQUERY(, , ) - -- ``collection``: The name of the property to iterate through -- ``variableName``: A variable name of the element to use in the subquery -- ``predicate``: The subquery predicate. - Use the variable specified by ``variableName`` to refer to the - currently-iterated element. - -A subquery iterates through the given collection and checks the given predicate -against each object in the collection. The predicate can refer to the current -iterated object with the variable name passed to ``SUBQUERY()``. - -A subquery expression resolves to a list of objects. -Realm only supports the ``@count`` aggregate operator on the result -of a subquery. This allows you to count how many objects in the subquery -input collection matched the predicate. - -You can use the count of the subquery result as you would any other number -in a valid expression. In particular, you can compare the count with the -number ``0`` to return all matching objects. +.. _rql-sort-distinct-limit: +Sort and Limit Operators +~~~~~~~~~~~~~~~~~~~~~~~~ -.. example:: +Use sort and limit operators to shape your query results collection. You can +combine these operators across multiple properties. - The following example shows two subquery filters on a collection of projects. + For example, if you ``SORT (priority DESC, name DESC)``, the query + returns sorted by priority, and then by name when priority + value is the same. - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.subquery.js - :language: js -.. _rql-sort-distinct-limit: -Sort, Distinct & Limit ----------------------- Sort and limit the results collection of your query using additional operators. .. list-table:: :header-rows: 1 - :widths: 40 60 + :widths: 20 80 * - Operator - Description - * - ``SORT`` + * - ``SORT`` (``ASC`` or ``DESC``) - Specify the name of the property to compare, and whether to sort by - ascending (``ASC``) or descending (``DESC``) order. If you specify + ascending (``ASC``) or descending (``DESC``) order. If you specify multiple SORT fields, you must specify sort order for each field. - With multiple sort fields, the query sorts by the first field, and - then the second. - - For example, if you ``SORT (priority DESC, name DESC)``, the query - returns sorted by priority, and then by name when priority - value is the same. + With multiple sort fields, the query sorts by the first field, and + then the second. * - ``DISTINCT`` - Specify a name of the property to compare. Remove duplicates @@ -1046,12 +370,30 @@ Sort and limit the results collection of your query using additional operators. - Enforcing uniqueness by name - Limiting the results to 5 items - .. literalinclude:: /examples/generated/realm-query-language/realm-query-language.snippet.sort-distinct-limit.js + .. literalinclude:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.js :language: javascript -.. _flexible-sync-rql-limitations: +.. important:: Order Matters + + Queries are executed in order. This includes the order of the operators in + the query *and* the order of properties within an operator, if applicable. + This can greatly impact the results returned. For example, sorting a query before + limiting it can return very different results than sorting *after* limiting + it. + + .. .. include:: /includes/file.rst + :start-after: text to start after (Optional} + :end-before: text to end before (Optional} + + For example, + + - ``LIMIT(5) SORT(priority DESC)`` returns + the top 5 items in the entire collection, which are then sorted by priority. However, ``SORT(priority DESC) LIMIT(5)`` + + +Data Type Queries +----------------- + + -Flexible Sync RQL Limitations ------------------------------ -.. include:: /includes/flex-sync-limitations.rst From 8180c3755b0a28794bb583c8846bea7f7be5f84c Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 23 May 2024 10:21:18 -0400 Subject: [PATCH 06/12] Upgrade to 12.9.0 for collections in mixed support --- .../v12/__tests__/models/rql-data-models.ts | 2 + .../__tests__/realm-query-language.test.js | 20 +- .../__tests__/realm-query-language.test.ts | 138 ++++++------ examples/node/v12/package-lock.json | 14 +- examples/node/v12/package.json | 4 +- .../query/rql-example-data-model.rst | 71 ++++++ .../query-engines/realm-query-language.txt | 210 +++++++++++++----- 7 files changed, 333 insertions(+), 126 deletions(-) create mode 100644 source/includes/sdk-examples/query/rql-example-data-model.rst diff --git a/examples/node/v12/__tests__/models/rql-data-models.ts b/examples/node/v12/__tests__/models/rql-data-models.ts index 59c60d2344..776e1d1b94 100644 --- a/examples/node/v12/__tests__/models/rql-data-models.ts +++ b/examples/node/v12/__tests__/models/rql-data-models.ts @@ -64,6 +64,7 @@ export class Project extends Realm.Object { quota?: number; comments?: Realm.Dictionary; projectLocation?: Office; + additionalInfo!: Realm.Mixed; static schema: ObjectSchema = { name: "Project", @@ -74,6 +75,7 @@ export class Project extends Realm.Object { quota: "int?", comments: "string?{}", projectLocation: "Office?", + additionalInfo: "mixed", }, primaryKey: "_id", }; diff --git a/examples/node/v12/__tests__/realm-query-language.test.js b/examples/node/v12/__tests__/realm-query-language.test.js index 8110961261..2ced76f64c 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.js +++ b/examples/node/v12/__tests__/realm-query-language.test.js @@ -64,7 +64,12 @@ describe("Realm Query Language Reference", () => { }, ], quota: 1, // doesn't meet quota - comments: { status: "Behind schedule", projectNumber: "70150" }, + comments: { + status: "Behind schedule", + projectNumber: 70150, + budget: 5000.0, + customerContact: ["Mina", "Devon"], + }, projectLocation: mainBranch, }); const project = realm.create(Project, { @@ -100,7 +105,11 @@ describe("Realm Query Language Reference", () => { }, ], quota: 1, // meets quota - comments: { status: "Ahead of schedule", projectNumber: "70187" }, + comments: { + status: "Ahead of schedule", + projectNumber: 70187, + startDate: new Date("2021-01-01"), + }, projectLocation: mainBranch, }); @@ -120,7 +129,12 @@ describe("Realm Query Language Reference", () => { }, ], quota: 11, // doesn't meet quota - comments: { status: "On track", projectNumber: "N/A" }, + comments: { + status: "On track", + projectNumber: 4444, + startDate: new Date("2021-02-01"), + budget: 10000.0, + }, projectLocation: austinBranch, }); }); diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts index 97dccebb9f..673075c14b 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.ts +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -65,6 +65,14 @@ describe("Realm Query Language Reference", () => { quota: 1, // doesn't meet quota comments: { status: "Behind schedule", projectNumber: "70150" }, projectLocation: mainBranch, + // Mixed property is of type dictionary of mixed values + // (date, list of strings, bool, and int) + additionalInfo: { + startDate: new Date("2021-01-01"), + customerContacts: ["Alice", "Bob"], + recurringCustomer: true, + budget: 10000, + }, }); const project = realm.create("Project", { _id: new BSON.ObjectId(), @@ -101,6 +109,8 @@ describe("Realm Query Language Reference", () => { quota: 1, // meets quota comments: { status: "Ahead of schedule", projectNumber: "70187" }, projectLocation: mainBranch, + // Mixed property is of type string + additionalInfo: "Customer is a VIP.", }); realm.create("Project", { @@ -121,6 +131,16 @@ describe("Realm Query Language Reference", () => { quota: 11, // doesn't meet quota comments: { status: "On track", projectNumber: "N/A" }, projectLocation: austinBranch, + // Mixed property is of type list, containing string and nested + // dictionary of mixed values (date, boolean, and int) + additionalInfo: [ + "Customer is difficult to work with.", + { + startDate: new Date("2021-03-01"), + recurringCustomer: false, + budget: 10000, + }, + ], }); }); }); @@ -470,31 +490,49 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const projects = realm.objects(Project); - const sortedUniqueAliItems = items.filtered( + const sortedItems = items.filtered( // :snippet-start: sort-distinct-limit - "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" - // :snippet-end: + // Find incomplete items, sort by `priority` + // in descending order, then sort equal `priority` + // values by `progressMinutes` in ascending order. + "isComplete == false SORT(priority DESC, progressMinutes ASC)" + // :remove-start: ); + expect(sortedItems[0].name).toBe("Demo template app"); + const distinctItems = items.filtered( + // :remove-end: - expect(sortedUniqueAliItems.length).toBe(1); - const query = + // Find high priority items, then remove from the results + // any items with duplicate `name` AND `assignee` values. + "priority >= 5 DISTINCT(name, assignee)" + // :remove-start: + ); + expect(distinctItems.length).toBe(6); + const limitItems = items.filtered( + // :remove-end: + // Find in-progress items, then return the first 10 results. + "progressMinutes > 0 && isComplete != true LIMIT(10)" + // :snippet-end: + ); + expect(limitItems[0].name).toBe("Write tests"); + const sortFirst = items.filtered( // :snippet-start: sort-distinct-limit-order-matters - "SORT(priority DESC) LIMIT(2) DISTINCT(name)"; - // Returns 2 items with the highest priority - // :remove-start: - const orderMatters = items.filtered( - "isComplete != true SORT(priority DESC) LIMIT(2) DISTINCT(name)" + // 1. Sorts by highest priority. + // 2. Returns the first item. + // 3. Remove duplicate names (N/A because a single + // item is always considered distinct). + "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" + // :remove-start: ); - expect(orderMatters.length).toBe(2); - const query2 = + const limitLast = items.filtered( // :remove-end: - "isComplete != true DISTINCT(name) SORT(priority DESC) LIMIT(2)"; - // Returns the first 2 uniquely named items with the highest priority - // :snippet-end: - const limitFirst = items.filtered( - "isComplete != true DISTINCT(name) SORT(priority DESC) LIMIT(2)" + + // 1. Removes any duplicates by name. + // 2. Sorts by highest priority. + // 3. Returns the first item. + "assignee == null DISTINCT(name) SORT(priority ASC) LIMIT(1)" + // :snippet-end: ); - console.log(limitFirst.toJSON()); }); test("Subquery queries", () => { @@ -672,58 +710,34 @@ describe("Realm Query Language Reference", () => { }); }); - describe("Type operator", () => { - // Uses a test-specific schema with mixed type - // TODO: Update main schema with mixed type property once collections-in-mixed is supported - const Mixed = { - name: "Mixed", - properties: { name: "string", mixedType: "mixed" }, - }; - let realm: Realm; - const path = "mixed.realm"; - - // Add, then delete objects for this test - beforeEach(async () => { - realm = await Realm.open({ - schema: [Mixed], - path, - }); - realm.write(() => { - realm.create("Mixed", { - name: "Marge", - mixedType: true, - }); - realm.create("Mixed", { - name: "Lisa", - mixedType: 22, - }); - realm.create("Mixed", { - name: "Bart", - mixedType: "carrumba", - }); - }); - }); - - afterEach(() => { - realm.close(); - Realm.deleteFile({ path }); - }); - + describe("Type operators", () => { test("Type operator", () => { - const mixed = realm.objects("Mixed"); - const mixedString = mixed.filtered( + const projects = realm.objects(Project); + const mixedString = projects.filtered( // :snippet-start: type-operator - "mixedType.@type == 'string'" + // Find projects with an `additionalInfo` property of + // string type. + "additionalInfo.@type == 'string'" + // :remove-start: + ); + const mixedCollection = projects.filtered( + // :remove-end: + // Find projects with an `additionalInfo` property of + // `collection` type, which matches list or dictionary types. + "additionalInfo.@type == 'collection'" // :remove-start: ); - const mixedBool = mixed.filtered( + const mixedBool = projects.filtered( // :remove-end: - "mixedType.@type == 'bool'" + // Find projects with an `additionalInfo` property of + // list type, where any list element is of type 'bool'. + "additionalInfo[*].@type == 'bool'" // :snippet-end: ); - expect(mixedString.length).toBe(1); - expect(mixedBool.length).toBe(1); + console.debug(mixedString[1].name + " and " + mixedBool[0].name); + // expect(mixedString.length).toBe(1); + // expect(mixedBool.length).toBe(1); }); }); diff --git a/examples/node/v12/package-lock.json b/examples/node/v12/package-lock.json index d51e9b2280..a2cd94e3d4 100644 --- a/examples/node/v12/package-lock.json +++ b/examples/node/v12/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "fs-extra": "^11.1.1", - "realm": "^12.8.0" + "realm": "^12.9.0" }, "devDependencies": { "@babel/core": "^7.21.8", @@ -7462,9 +7462,9 @@ } }, "node_modules/realm": { - "version": "12.8.0", - "resolved": "https://registry.npmjs.org/realm/-/realm-12.8.0.tgz", - "integrity": "sha512-U1w5+ncyURQFQTrshoGn3KV+pzR1rQlPT7s3Sw6HPIPVBH80EWU3mirwvqp6RQ+Qi32ctRrBMTNeGd5mzAyiSw==", + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/realm/-/realm-12.9.0.tgz", + "integrity": "sha512-K7JblaSaqqFEu8kObgTCo1ITTYnR8rXYBdb5/5VXxD4VNKQVlrnO6Z4GhxDlohubmF8eNvRdC2wlHAsv2aUsOg==", "hasInstallScript": true, "dependencies": { "@realm/fetch": "^0.1.1", @@ -13846,9 +13846,9 @@ } }, "realm": { - "version": "12.8.0", - "resolved": "https://registry.npmjs.org/realm/-/realm-12.8.0.tgz", - "integrity": "sha512-U1w5+ncyURQFQTrshoGn3KV+pzR1rQlPT7s3Sw6HPIPVBH80EWU3mirwvqp6RQ+Qi32ctRrBMTNeGd5mzAyiSw==", + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/realm/-/realm-12.9.0.tgz", + "integrity": "sha512-K7JblaSaqqFEu8kObgTCo1ITTYnR8rXYBdb5/5VXxD4VNKQVlrnO6Z4GhxDlohubmF8eNvRdC2wlHAsv2aUsOg==", "requires": { "@realm/fetch": "^0.1.1", "bson": "^4.7.2", diff --git a/examples/node/v12/package.json b/examples/node/v12/package.json index 70ba51024f..2aa2508fb3 100644 --- a/examples/node/v12/package.json +++ b/examples/node/v12/package.json @@ -5,7 +5,7 @@ "main": "index.js", "type": "module", "scripts": { - "test": "jest --runInBand --detectOpenHandles --forceExit", + "test": "jest --runInBand --detectOpenHandles --silent=false --forceExit", "posttest": "npm run delete-realm-files", "test:js": "jest --selectProjects JavaScript --runInBand --detectOpenHandles --forceExit; npm run delete-realm-files", "test:ts": "NODE_OPTIONS=--experimental-vm-modules jest --selectProjects TypeScript --runInBand --detectOpenHandles --forceExit; npm run delete-realm-files", @@ -15,7 +15,7 @@ "license": "ISC", "dependencies": { "fs-extra": "^11.1.1", - "realm": "^12.8.0" + "realm": "^12.9.0" }, "devDependencies": { "@babel/core": "^7.21.8", diff --git a/source/includes/sdk-examples/query/rql-example-data-model.rst b/source/includes/sdk-examples/query/rql-example-data-model.rst new file mode 100644 index 0000000000..7f866902ab --- /dev/null +++ b/source/includes/sdk-examples/query/rql-example-data-model.rst @@ -0,0 +1,71 @@ +.. tabs-drivers:: + + tabs: + - id: cpp + content: | + + .. literalinclude:: /examples/generated/cpp/asymmetric-sync.snippet.create-asymmetric-object.cpp + :language: cpp + + - id: csharp + content: | + + .. literalinclude:: /examples/generated/dotnet/RqlSchemaExamples.snippet.rql-schema-examples.cs + :language: csharp + + - id: dart + content: | + + .. literalinclude:: /examples/generated/flutter/task_project_models_test.snippet.task-project-models.dart + :language: dart + + - id: java + content: | + + .. code-block:: java + + public class Item extends RealmObject { + ObjectId id = new ObjectId(); + String name; + Boolean isComplete = false; + String assignee; + Integer priority = 0; + Integer progressMinutes = 0; + @LinkingObjects("items") + final RealmResults projects = null; + } + public class Project extends RealmObject { + ObjectId id = new ObjectId(); + String name; + RealmList items; + Integer quota = null; + } + + - id: javascript + content: | + + .. literalinclude:: /examples/generated/node/rql-data-models.snippet.rql-data-models.js + :language: javascript + + - id: kotlin + content: | + + .. literalinclude:: /examples/generated/kotlin/RQLTest.snippet.rql-schema-example.kt + :language: kotlin + + - id: objectivec + content: | + + .. literalinclude:: /examples/MissingPlaceholders/api.m + :language: objectivec + + - id: swift + content: | + + .. literalinclude:: /examples/MissingPlaceholders/api.swift + :language: swift + + - id: typescript + content: | + + .. include:: /examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index 3eb1f675e5..6220062176 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -80,16 +80,41 @@ See the schema for these two classes, ``Project`` and ``Item``, below: Query Syntax ------------ +Expressions and Predicates +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Realm Query Language uses expressions and predicates to evaluate queries. -Dot Notation -~~~~~~~~~~~~ +- **Expressions** are the building blocks of queries. They can be simple or complex. + For example, ``name == 'Ali'`` is a simple expression, while + ``name == 'Ali' AND priority > 5`` is a complex expression. +- **Predicates** are expressions that evaluate to ``true`` or ``false``. + For example, ``name == 'Ali'`` is a predicate that evaluates to ``true`` + if the name property is 'Ali'. -You can use **dot notation** to refer to child properties of an object, including the properties of embedded objects and relationships: +TRUEPREDICATE and FALSEPREDICATE + +Case Sensitivity +~~~~~~~~~~~~~~~~ + +Unless otherwise noted, RQL operators and keywords are case insensitive. + +``[c]`` denotes case sensitivity in the following examples. + +Dot & Bracket Notation +~~~~~~~~~~~~~~~~~~~~~~ + +.. TODO: confirm how we want to communicate which SDK versions support bracket notation + +You can use **dot notation** or **bracket notation** to refer to child +properties of an object, including the properties of embedded objects and +relationships: + +.. TODO: add bracket notation to example .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst -You can also chain dot notations for nested properties. +You can also chain these notations for nested properties. For example, each Project has a ``projectLocation`` property that refers to an Office object, which itself contains an embedded object property ``address``. You can chain dot notations to query the deeply nested @@ -98,9 +123,7 @@ property ``address``. You can chain dot notations to query the deeply nested .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst -.. TODO: add as part of collections-in-mixed epic -Bracket Notation -~~~~~~~~~~~~~~~~ + .. _rql-parameterized-queries: Parameterized vs. Serialized Queries @@ -218,6 +241,78 @@ property values match certain criteria: including decimal, float, and Decimal128. +.. _rql-string-operators: + +String Operators +~~~~~~~~~~~~~~~~ + +Compare string values using these string operators. +Regex-like wildcards allow more flexibility in search. + +.. note:: + + You can use the following modifiers with the string operators: + + - ``[c]`` for case insensitivity. + + .. code-block:: javascript + + "name CONTAINS[c] $0", 'a' + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Operator + - Description + + * - | ``BEGINSWITH`` + - Evaluates to ``true`` if the left-hand string expression begins with + the right-hand string expression. This is similar to ``contains``, + but only matches if the right-hand string expression is found + at the beginning of the left-hand string expression. + + * - | ``CONTAINS`` + - Evaluates to ``true`` if the right-hand string expression + is found anywhere in the left-hand string expression. + + * - | ``ENDSWITH`` + - Evaluates to ``true`` if the left-hand string expression ends + with the right-hand string expression. This is similar to ``contains``, + but only matches if the left-hand string expression is found + at the very end of the right-hand string expression. + + * - | ``LIKE`` + - Evaluates to ``true`` if the left-hand string expression + matches the right-hand string wildcard string + expression. A wildcard string expression is a string + that uses normal characters with two special wildcard + characters: + + - The ``*`` wildcard matches zero or more of any character + - The ``?`` wildcard matches any character. + + For example, the wildcard string "d?g" matches "dog", + "dig", and "dug", but not "ding", "dg", or "a dog". + + * - | ``==``, ``=`` + - Evaluates to ``true`` if the left-hand string is lexicographically equal + to the right-hand string. + + * - | ``!=``, ``<>`` + - Evaluates to ``true`` if the left-hand string is not lexicographically + equal to the right-hand string. + +.. example:: + + We use the query engine's string operators to find: + + - Projects with a name starting with the letter 'e' + - Projects with names that contain 'ie' + + .. literalinclude:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.js + :language: javascript + .. _rql-logical-operators: Logical Operators @@ -282,6 +377,7 @@ The following example uses arithmetic operators on Item object properties contai Aggregate Operators ~~~~~~~~~~~~~~~~~~~ +.. TODO: link to collection query section Aggregate operators traverse a collection and reduce it to a single value. You can use aggregate operators on collection properties, such as a list, or on @@ -314,27 +410,19 @@ You can use aggregate operators on collection properties, such as a list, or on excluding ``null`` values. -The following example uses aggregate operators to find project whose ``items`` +The following example uses aggregate operators to find projects whose ``items`` collection property meets certain criteria: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst .. _rql-sort-distinct-limit: -Sort and Limit Operators -~~~~~~~~~~~~~~~~~~~~~~~~ - -Use sort and limit operators to shape your query results collection. You can -combine these operators across multiple properties. - - For example, if you ``SORT (priority DESC, name DESC)``, the query - returns sorted by priority, and then by name when priority - value is the same. +Sort, Distinct, and Limit Operators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - - -Sort and limit the results collection of your query using additional operators. +Use sort, distinct, and limit operators to shape your query results collection. You can +combine these operators in a single query across multiple properties. Operators +are applied in the order they appear in the query. .. list-table:: :header-rows: 1 @@ -344,51 +432,69 @@ Sort and limit the results collection of your query using additional operators. - Description * - ``SORT`` (``ASC`` or ``DESC``) - - Specify the name of the property to compare, and whether to sort by - ascending (``ASC``) or descending (``DESC``) order. If you specify - multiple SORT fields, you must specify sort order for each field. - With multiple sort fields, the query sorts by the first field, and - then the second. + - Sort the results collection by the specified property or properties, either in ascending (``ASC``) or descending + (``DESC``) order. Separate multiple properties by comma and define the + sort order for each property. The SDK applies each sort operation one at a time, in order. * - ``DISTINCT`` - - Specify a name of the property to compare. Remove duplicates - for that property in the results collection. If you specify multiple - DISTINCT fields, the query removes duplicates by the first field, and - then the second. For example, if you ``DISTINCT (name, assignee)``, - the query only removes duplicates where the values of both properties - are the same. + - Remove duplicates of the specified property or properties from the + results collection. Separate multiple properties by comma. The SDK + applies all distinct operations as a single AND condition, + where duplicates must match all specified properties. * - ``LIMIT`` - Limit the results collection to the specified number. -.. example:: +The following example finds all incomplete items, then +shapes the returned results using sort, distinct, and limit operators: - Use the query engine's sort, distinct, and limit operators to find to-do items - where the assignee is Ali: +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst - - Sorted by priority in descending order - - Enforcing uniqueness by name - - Limiting the results to 5 items +.. important:: Order Matters - .. literalinclude:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.js - :language: javascript + The SDK executes queries in order. This includes the order of any ``SORT``, ``DISTINCT``, and ``LIMIT`` operators in + the query *and* the order of any properties within those operators. + This can greatly impact the results returned. For example, sorting a query + before limiting it can return very different results than sorting *after* + limiting it. -.. important:: Order Matters + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst + + +Data Type Operators +------------------- + +.. _rql-type-operator: + +Type Operator +~~~~~~~~~~~~~ + +Check the data type of a mixed type or dictionary property using the +``@type`` operator. Evaluate the property against a string representation of the +data type name using string comparison operators. - Queries are executed in order. This includes the order of the operators in - the query *and* the order of properties within an operator, if applicable. - This can greatly impact the results returned. For example, sorting a query before - limiting it can return very different results than sorting *after* limiting - it. +For information on how each SDK language's data types map to database-specific data types, refer to :ref:`sdks-data-types`. + +You can currently only use the type operator with mixed types and +dictionaries. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Operator + - Description - .. .. include:: /includes/file.rst - :start-after: text to start after (Optional} - :end-before: text to end before (Optional} + * - ``@type`` + - Check if type of a property is the specified data type represented as a string. + Use ``==`` and ``!=`` to compare equality. - For example, +The following example uses the ``@type`` operator to find projects +whose mixed data type ``additionalInfo`` property type matches specific +criteria: - - ``LIMIT(5) SORT(priority DESC)`` returns - the top 5 items in the entire collection, which are then sorted by priority. However, ``SORT(priority DESC) LIMIT(5)`` +.. literalinclude:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.js + :language: js Data Type Queries From 0183b3b224a2f5567750819f5db1ddfefb600cdd Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 30 May 2024 12:48:56 -0400 Subject: [PATCH 07/12] Rearranged page order and updated example snippet formatting --- .../__tests__/realm-query-language.test.ts | 262 ++++--- ...ippet.backlinks-aggregate-operators.ts.rst | 9 - ...uage.test.snippet.backlinks-atLinks.ts.rst | 4 +- ...ppet.backlinks-collection-operators.ts.rst | 27 +- ...st.snippet.backlinks-linkingObjects.ts.rst | 1 + ...guage.test.snippet.basic-arithmetic.ts.rst | 9 +- ...e.test.snippet.comparison-operators.ts.rst | 3 - ...st.snippet.date-parameterized-query.ts.rst | 3 +- ...uage.test.snippet.deep-dot-notation.ts.rst | 2 + ...e.test.snippet.dictionary-operators.ts.rst | 30 +- ...-language.test.snippet.dot-notation.ts.rst | 5 + ...ippet.equivalent-lists-any-operator.ts.rst | 7 + ...snippet.list-comparisons-collection.ts.rst | 2 + ...ppet.list-comparisons-parameterized.ts.rst | 2 + ...est.snippet.list-comparisons-static.ts.rst | 2 + ...uery-language.test.snippet.nil-type.ts.rst | 5 +- ...y-language.test.snippet.oid-literal.ts.rst | 3 - ...alm-query-language.test.snippet.oid.ts.rst | 17 +- ...query-language.test.snippet.rql-fts.ts.rst | 4 +- ...language.test.snippet.set-operators.ts.rst | 7 +- ...t.sort-distinct-limit-order-matters.ts.rst | 12 + ...ge.test.snippet.sort-distinct-limit.ts.rst | 11 +- ...guage.test.snippet.string-operators.ts.rst | 20 +- ...anguage.test.snippet.subquery-count.ts.rst | 5 - ...uery-language.test.snippet.subquery.ts.rst | 8 +- ...language.test.snippet.type-operator.ts.rst | 12 +- ...lm-query-language.test.snippet.uuid.ts.rst | 3 - ...data-models.snippet.rql-data-models.ts.rst | 2 + .../query-engines/realm-query-language.txt | 708 +++++++++++++----- 29 files changed, 844 insertions(+), 341 deletions(-) delete mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst delete mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst create mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst delete mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst delete mode 100644 source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts index 673075c14b..d8d0bca06d 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.ts +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -16,7 +16,7 @@ describe("Realm Query Language Reference", () => { name: "Main Branch", address: { name: "Main Branch", - street: "123 Main St", + street: "999 Big Boulevard", zipcode: 10019, }, }; @@ -65,7 +65,7 @@ describe("Realm Query Language Reference", () => { quota: 1, // doesn't meet quota comments: { status: "Behind schedule", projectNumber: "70150" }, projectLocation: mainBranch, - // Mixed property is of type dictionary of mixed values + // Mixed property is of type dictionary of mixed values // (date, list of strings, bool, and int) additionalInfo: { startDate: new Date("2021-01-01"), @@ -131,7 +131,7 @@ describe("Realm Query Language Reference", () => { quota: 11, // doesn't meet quota comments: { status: "On track", projectNumber: "N/A" }, projectLocation: austinBranch, - // Mixed property is of type list, containing string and nested + // Mixed property is of type list, containing string and nested // dictionary of mixed values (date, boolean, and int) additionalInfo: [ "Customer is difficult to work with.", @@ -336,9 +336,9 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects(Project); const startWithE = projects.filtered( // :snippet-start: string-operators - // Find projects whose name starts with the letter 'e' + // Find projects whose name starts with 'E' or 'e' // (case-insensitive). - "name BEGINSWITH[c] $0", "e" + "name BEGINSWITH[c] $0", "E" // :remove-start: ); expect(startWithE.length).toBe(1); @@ -346,13 +346,39 @@ describe("Realm Query Language Reference", () => { const containIe = projects.filtered( // :remove-end: - // Find projects whose name contains the letters 'ie' + // Find projects whose name contains 'ie' // (case-sensitive). "name CONTAINS $0", "ie" - // :snippet-end: + // :remove-start: ); expect(containIe.length).toBe(0); }); + + test("String comparisons", () => { + const projects = realm.objects(Project); + const items = realm.objects(Item); + // prettier-ignore + const assigneeBetween = items.filtered( + // :remove-end: + + // Find items where the assignee name is lexicographically + // between 'Ali' and 'Chris' (case-sensitive). + "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" + // :remove-start: + ); + // prettier-ignore + const compareStreet = projects.filtered( + // :remove-end: + + // Find projects where the street address is lexicographically + // greater than '123 Main St' (case-sensitive). + "projectLocation.address.street > $0", "123 Main St" + // :snippet-end: + ); + + expect(compareStreet.length).toBe(2); + expect(assigneeBetween.length).toBe(2); + }); }); // prettier-ignore @@ -407,8 +433,8 @@ describe("Realm Query Language Reference", () => { expect(longRunningProjects.length).toBe(1); }); - describe("Collection queries", () => { - test("Collection operators", () => { + describe("Collection operators", () => { + test("Collection queries", () => { const projects = realm.objects(Project); // prettier-ignore const noCompleteItems = projects.filtered( @@ -421,8 +447,8 @@ describe("Realm Query Language Reference", () => { const anyTopPriorityItems = projects.filtered( // :remove-end: - // Find projects that contain an item with priority 10. - "ANY items.priority == $0", 10 + // Find projects that contain any item with priority 10. + "items.priority == $0", 10 // (ANY operator is implied.) // :remove-start: ); // prettier-ignore @@ -446,7 +472,8 @@ describe("Realm Query Language Reference", () => { const notAssignedToAlexOrAli = projects.filtered( // :remove-end: - // Projects with no items assigned to either Alex or Ali. + // Find projects with no items assigned to either + // Alex or Ali. "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" // :snippet-end: ); @@ -464,11 +491,15 @@ describe("Realm Query Language Reference", () => { const collectionQuery = projects.filtered( // :snippet-start: list-comparisons-collection + // Find an item with the specified ObjectId value + // in the `items` collection. "oid(631a072f75120729dc9223d9) IN items._id" // :snippet-end: ); const staticQuery = items.filtered( // :snippet-start: list-comparisons-static + // Find items with a priority value matching + // any value in the static list. "priority IN {0, 1, 2}" // :snippet-end: ); @@ -478,9 +509,33 @@ describe("Realm Query Language Reference", () => { new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; + // Find items with an ObjectId value matching any value in the + // parameterized list. const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); // :snippet-end: + // prettier-ignore + const anyOperator = items.filtered( + // :snippet-start: equivalent-lists-any-operator + "assignee == ANY { $0, $1 }", "Alex", "Ali" + // :remove-start: + ); + // prettier-ignore + const equivalentAnyOperator = items.filtered( + // :remove-end: + + "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) + // :remove-start: + ); + const equivalentNoneOperator = items.filtered( + // :remove-end: + + "assignee NONE { 'Alex', 'Ali' }" // Equivalent to != ANY. + // :snippet-end: + ); + + expect(anyOperator.length).toBe(2); + expect(equivalentAnyOperator.length).toBe(2); expect(collectionQuery.length).toBe(1); expect(staticQuery.length).toBe(1); expect(parameterizedQuery.length).toBe(3); @@ -535,94 +590,79 @@ describe("Realm Query Language Reference", () => { ); }); - test("Subquery queries", () => { - const projects = realm.objects(Project); - const subquery = projects.filtered( - // :snippet-start: subquery - // Find projects with incomplete to-do items assigned to Alex. - "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" - // :snippet-end: - ); - expect(subquery.length).toBe(1); - expect(subquery[0].name).toBe("Example Project with Items"); - - const subquery2 = projects.filtered( - // :snippet-start: subquery-count - // Find projects where the number of completed to-do items - // is greater than or equal to the project's `quota` property. - "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" - // :snippet-end: - ); - - expect(subquery2.length).toBe(1); - expect(subquery2[0].name).toBe("Project that Meets Quota"); - }); + test("Subquery query", () => { + const projects = realm.objects("Project"); + const subquery = projects.filtered( + // :snippet-start: subquery + // Find projects with incomplete items with 'Demo' in the name. + "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" + // :remove-start: + ); + expect(subquery.length).toBe(1); + expect(subquery[0].name).toBe("Project that Meets Quota"); + + const subquery2 = projects.filtered( + // :remove-end: + + // Find projects where the number of completed items + // is greater than or equal to the project's `quota` property. + "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" + // :snippet-end: + ); + + expect(subquery2.length).toBe(1); + expect(subquery2[0].name).toBe("Project that Meets Quota"); + }); // prettier-ignore test("Dictionary operators", () => { const dictionaries = realm.objects(Project); const statusKey = dictionaries.filtered( // :snippet-start: dictionary-operators - // Find `comments` dictionary properties with key 'status'. + // Find projects whose `comments` dictionary property + // have a key of 'status'. "comments.@keys == $0", "status" // :remove-start: ); const statusOnTrack = dictionaries.filtered( // :remove-end: - // Find `comments` dictionary properties with key 'status' - // and value 'On track'. - "comments['status'] == $0", "On track" + // Find projects whose `comments` dictionary property + // have a 'status' key with a value that ends in 'track'. + "comments['status'] LIKE $0", "*track" + // :remove-start: ); const numItemsInDict = dictionaries.filtered( // :remove-end: - // Find `comments` dictionary properties with - // more than one key-value pair. + // Find projects whose `comments` dictionary property + // have more than one key-value pair. "comments.@count > $0", 1 // :remove-start: ); - const hasString = dictionaries.filtered( - // :remove-end: - // Find `comments` dictionary properties where ANY - // values are of type 'string`. - "ANY comments.@type == 'string'" - // :remove-start: - ); - - const hasStringImplied = dictionaries.filtered( + const allString = dictionaries.filtered( // :remove-end: - "comments.@type == 'string'" // (Equivalent - ANY is implied.) - - // :remove-start: - ); - - const allInt = dictionaries.filtered( - // :remove-end: - // Find `comments` dictionary properties where ALL - // values are of type 'int'. - "ALL comments.@type == 'int'" + // Find projects whose `comments` dictionary property + // contains only values of type 'string'. + "ALL comments.@type == 'string'" // :remove-start: ); const noInts = dictionaries.filtered( // :remove-end: - // Find `comments` dictionary properties where NO - // values are of type 'int'. + // Find projects whose `comments` dictionary property + // contains no values of type 'int'. "NONE comments.@type == 'int'" - // :snippet-end: ); expect(statusKey.length).toBe(3); expect(statusOnTrack.length).toBe(1); expect(numItemsInDict.length).toBe(3); - expect(hasString.length).toBe(3); - expect(hasStringImplied.length).toBe(3); - expect(allInt.length).toBe(0); + expect(allString.length).toBe(3); expect(noInts.length).toBe(3); }); }); @@ -631,8 +671,8 @@ describe("Realm Query Language Reference", () => { test("Backlinks query @links", () => { const atLinksResult = realm.objects(Item).filtered( // :snippet-start: backlinks-atLinks - // Find items that belong to a project with a quota - // less than 10 (using '@links'). + // Find items that belong to a project with a quota less than 10 + // (using '@links..'). "@links.Project.items.quota < 10" // :snippet-end: ); @@ -641,6 +681,7 @@ describe("Realm Query Language Reference", () => { const linkingObjectsResult = realm.objects(Item).filtered( // :snippet-start: backlinks-linkingObjects // Find items that belong to a project with a quota greater than 10 + // through the Item object's `projects` property // (using 'LinkingObjects'). "projects.quota > 10" // :snippet-end: @@ -651,27 +692,30 @@ describe("Realm Query Language Reference", () => { test("Backlinks collection operators", () => { const anyResult = realm.objects(Item).filtered( // :snippet-start: backlinks-collection-operators - // Find items where ANY project that references the item + // Find items where no project that references the item // has a quota greater than 10. - "ANY @links.Project.items.quota > 10" + "NONE @links.Project.items.quota > 10" // :remove-start: ); - expect(anyResult.length).toBe(2); + expect(anyResult.length).toBe(5); const allResult = realm.objects(Item).filtered( // :remove-end: - // Find items where ALL projects that reference the item + + // Find items where all projects that reference the item // have a quota less than 5. "ALL @links.Project.items.quota < 5" - // :snippet-end: + // :remove-start: + ); expect(allResult.length).toBe(5); }); test("Backlinks aggregate operators", () => { const shallowResultLinkingObjects = realm.objects(Item).filtered( - // :snippet-start: backlinks-aggregate-operators - // Find items that are referenced by multiple projects + // :remove-end: + + // Find items that are referenced by multiple projects. "projects.@count > 1" // :remove-start: ); @@ -680,7 +724,8 @@ describe("Realm Query Language Reference", () => { const shallowResultAtLinks = realm.objects(Item).filtered( // :remove-end: - // Find items that are not referenced by any project + + // Find items that are not referenced by any project. "@links.Project.items.@count == 0" // :remove-start: ); @@ -689,10 +734,11 @@ describe("Realm Query Language Reference", () => { const deepResultAtLinks = realm.objects(Item).filtered( // :remove-end: + // Find items that belong to a project where the average item has - // been worked on for at least 5 minutes + // been worked on for at least 10 minutes "@links.Project.items.items.@avg.progressMinutes > 10" - // :snippet-end: + // :remove-start: ); expect(deepResultAtLinks.length).toBe(2); expect(deepResultAtLinks[0].name).toBe("Write tests"); @@ -700,8 +746,10 @@ describe("Realm Query Language Reference", () => { test("Count all backlinks (@links.@count)", () => { const result = realm.objects(Item).filtered( - // :snippet-start: backlinks-atCount - // Find items that are not referenced by another object of any type + // :remove-end: + + // Find items that are not referenced by another + // object of any type (backlink count is 0). "@links.@count == 0" // :snippet-end: ); @@ -722,7 +770,8 @@ describe("Realm Query Language Reference", () => { ); const mixedCollection = projects.filtered( // :remove-end: - // Find projects with an `additionalInfo` property of + + // Find projects with an `additionalInfo` property of // `collection` type, which matches list or dictionary types. "additionalInfo.@type == 'collection'" // :remove-start: @@ -730,14 +779,13 @@ describe("Realm Query Language Reference", () => { const mixedBool = projects.filtered( // :remove-end: - // Find projects with an `additionalInfo` property of + // Find projects with an `additionalInfo` property of // list type, where any list element is of type 'bool'. "additionalInfo[*].@type == 'bool'" // :snippet-end: ); - console.debug(mixedString[1].name + " and " + mixedBool[0].name); - // expect(mixedString.length).toBe(1); - // expect(mixedBool.length).toBe(1); + expect(mixedString.length).toBe(1); + expect(mixedBool.length).toBe(1); }); }); @@ -774,14 +822,14 @@ describe("Realm Query Language Reference", () => { const oidValueString = "6001c033600510df3bbfd864"; const uuid1String = "d1b186e1-e9e0-4768-a1a7-c492519d47ee"; const oidValue = new BSON.ObjectId(oidValueString); - const uuid1 = new BSON.UUID(uuid1String); + const uuidValue = new BSON.UUID(uuid1String); // Add, then delete objects for this test beforeEach(async () => { realm = await Realm.open({ schema: [OidUuid], path }); const obj1 = { _id: oidValue, - id: uuid1, + id: uuidValue, }; const obj2 = { _id: new BSON.ObjectId(), @@ -798,28 +846,47 @@ describe("Realm Query Language Reference", () => { Realm.deleteFile({ path }); }); - test("ObjectId Operator", () => { + test("ObjectId query", () => { const oidUuids = realm.objects("OidUuid"); + // prettier-ignore const oidStringLiteral = oidUuids.filtered( // :snippet-start: oid + // Find an item whose `_id` matches the ObjectID + // value passed to 'oid()'. "_id == oid(6001c033600510df3bbfd864)" - // :snippet-end: + // :remove-start: ); - // prettier-ignore + const oidInterpolation = oidUuids.filtered( - // :snippet-start:oid-literal + // :remove-end: + + // Find an item whose `_id` matches the ObjectID + // passed as a parameterized query argument. "_id == $0", oidValue - // :snippet-end: + // :remove-start: ); expect(oidStringLiteral.length).toBe(1); expect(oidInterpolation.length).toBe(1); }); - test("UUID Operator", () => { + test("UUID query", () => { const oidUuids = realm.objects("OidUuid"); const uuid = oidUuids.filtered( - // :snippet-start: uuid + // :remove-end: + + // Find an item whose `id` matches the UUID value + // passed to 'uuid()'. "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" + + // :remove-start: + ); + // prettier-ignore + const test = oidUuids.filtered( + // :remove-end: + + // Find an item whose `_id` matches the UUID + // passed as a parameterized query argument. + "id == $0", uuidValue // :snippet-end: ); expect(uuid.length).toBe(1); @@ -876,13 +943,14 @@ describe("Realm Query Language Reference", () => { // :snippet-start: date-parameterized-query // Find to-do items completed before today's date. "dateCompleted < $0", today - // :remove-start: ); const dateAlt1 = dates.filtered( // :remove-end: - // Find to-do items completed this year until today. + + // Find to-do items completed between the start of the year + // until today. "dateCompleted > $0 AND dateCompleted < $1", thisYear, today // :snippet-end: ); @@ -915,8 +983,8 @@ describe("Realm Query Language Reference", () => { const itemsStartingWithWri = items.filtered( // :remove-end: - // Use '*' to match any suffix characters: - // Find items starting with 'wri-'. + // Use '*' to match any characters after a prefix: + // Find items with a name that starts with 'wri'. "name TEXT $0", "wri*" // :snippet-end: ); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst deleted file mode 100644 index 3388676d86..0000000000 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-aggregate-operators.ts.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. code-block:: typescript - - // Find items that are referenced by multiple projects - "projects.@count > 1" - // Find items that are not referenced by any project - "@links.Project.items.@count == 0" - // Find items that belong to a project where the average item has - // been worked on for at least 5 minutes - "@links.Project.items.items.@avg.progressMinutes > 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst index 8346571665..e877dfd1f9 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst @@ -1,5 +1,5 @@ .. code-block:: typescript - // Find items that belong to a project with a quota - // less than 10 (using '@links'). + // Find items that belong to a project with a quota less than 10 + // (using '@links..'). "@links.Project.items.quota < 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst index be0e56a7f9..fa70358f91 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst @@ -1,8 +1,23 @@ .. code-block:: typescript - // Find items where ANY project that references the item - // has a quota greater than 10. - "ANY @links.Project.items.quota > 10" - // Find items where ALL projects that reference the item - // have a quota less than 5. - "ALL @links.Project.items.quota < 5" + // Find items where no project that references the item + // has a quota greater than 10. + "NONE @links.Project.items.quota > 10" + + // Find items where all projects that reference the item + // have a quota less than 5. + "ALL @links.Project.items.quota < 5" + + // Find items that are referenced by multiple projects. + "projects.@count > 1" + + // Find items that are not referenced by any project. + "@links.Project.items.@count == 0" + + // Find items that belong to a project where the average item has + // been worked on for at least 10 minutes + "@links.Project.items.items.@avg.progressMinutes > 10" + + // Find items that are not referenced by another + // object of any type (backlink count is 0). + "@links.@count == 0" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst index 7269485ca6..e1a9e51086 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst @@ -1,5 +1,6 @@ .. code-block:: typescript // Find items that belong to a project with a quota greater than 10 + // through the Item object's `projects` property // (using 'LinkingObjects'). "projects.quota > 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst index 5e23fdbb10..f58f72e118 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst @@ -1,5 +1,8 @@ .. code-block:: typescript - // Find items with a `priority` greater than 3. - "2 * priority > 6" // `priority > 3` - "priority >= 2 * (2 - 1) + 2" // `priority >= 4` + // Evaluate against an item's `priority` property value: + "2 * priority > 6" // resolves to `priority > 3` + "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` + + // Evaluate against multiple object property values: + "progressMinutes * priority == 90" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst index 34128a6378..25061aab11 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst @@ -3,9 +3,6 @@ // Compare `priority` values against a threshold value. "priority > $0", 5 - // Compare `progressMinutes` values against a threshold value. - "progressMinutes > $0", 120 - // Compare `assignee` values to `null` value. "assignee == $0", null diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst index fd06d334ce..f83e455b95 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst @@ -3,5 +3,6 @@ // Find to-do items completed before today's date. "dateCompleted < $0", today - // Find to-do items completed this year until today. + // Find to-do items completed between the start of the year + // until today. "dateCompleted > $0 AND dateCompleted < $1", thisYear, today diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst index db769f001a..6e20a8cfe1 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst @@ -1,3 +1,5 @@ .. code-block:: typescript + // Find projects whose `projectLocation` property contains + // an embedded Address object with a specific zip code. "projectLocation.address.zipcode == 10019" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst index 1f883a4627..8b2bed7db4 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst @@ -1,25 +1,21 @@ .. code-block:: typescript - // Find `comments` dictionary properties with key 'status'. + // Find projects whose `comments` dictionary property + // have a key of 'status'. "comments.@keys == $0", "status" - // Find `comments` dictionary properties with key 'status' - // and value 'On track'. - "comments['status'] == $0", "On track" - // Find `comments` dictionary properties with - // more than one key-value pair. - "comments.@count > $0", 1 + // Find projects whose `comments` dictionary property + // have a 'status' key with a value that ends in 'track'. + "comments['status'] LIKE $0", "*track" - // Find `comments` dictionary properties where ANY - // values are of type 'string`. - "ANY comments.@type == 'string'" - "comments.@type == 'string'" // (Equivalent - ANY is implied.) + // Find projects whose `comments` dictionary property + // have more than one key-value pair. + "comments.@count > $0", 1 - // Find `comments` dictionary properties where ALL - // values are of type 'int'. - "ALL comments.@type == 'int'" + // Find projects whose `comments` dictionary property + // contains only values of type 'string'. + "ALL comments.@type == 'string'" - // Find `comments` dictionary properties where NO - // values are of type 'int'. + // Find projects whose `comments` dictionary property + // contains no values of type 'int'. "NONE comments.@type == 'int'" - diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst new file mode 100644 index 0000000000..011a3715b4 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst @@ -0,0 +1,5 @@ +.. code-block:: typescript + + // Find projects whose `items` list property contains + // an Item object with a specific name. + "items[0].name == 'Approve project plan'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst new file mode 100644 index 0000000000..f35fae515e --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst @@ -0,0 +1,7 @@ +.. code-block:: typescript + + "assignee == ANY { $0, $1 }", "Alex", "Ali" + + "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) + + "assignee NONE { 'Alex', 'Ali' }" // Equivalent to != ANY. diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst index 290b29341e..ab5fef1b83 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst @@ -1,3 +1,5 @@ .. code-block:: typescript + // Find an item with the specified ObjectId value + // in the `items` collection. "oid(631a072f75120729dc9223d9) IN items._id" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst index 0641020373..5a3fc8f1d4 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst @@ -5,4 +5,6 @@ new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; + // Find items with an ObjectId value matching any value in the + // parameterized list. const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst index e79c902584..df932d00da 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst @@ -1,3 +1,5 @@ .. code-block:: typescript + // Find items with a priority value matching + // any value in the static list. "priority IN {0, 1, 2}" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst index 38ea382f9b..91769b4891 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst @@ -1,3 +1,6 @@ .. code-block:: typescript - "assignee == nil" + "assignee == nil" + + // 'null' maps to the SDK language's null pointer + "assignee == $0", null diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst deleted file mode 100644 index 1b7ee896b1..0000000000 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid-literal.ts.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. code-block:: typescript - - "_id == $0", oidValue diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst index a7909effbe..cb00dbe046 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst @@ -1,3 +1,18 @@ .. code-block:: typescript - "_id == oid(6001c033600510df3bbfd864)" + // Find an item whose `_id` matches the ObjectID + // value passed to 'oid()'. + "_id == oid(6001c033600510df3bbfd864)" + + // Find an item whose `_id` matches the ObjectID + // passed as a parameterized query argument. + "_id == $0", oidValue + + // Find an item whose `id` matches the UUID value + // passed to 'uuid()'. + "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" + + + // Find an item whose `_id` matches the UUID + // passed as a parameterized query argument. + "id == $0", uuidValue diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst index b861e87002..ac69dc328e 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst @@ -7,6 +7,6 @@ // Find items with 'write' but not 'tests' in the name. "name TEXT $0", "write -tests" - // Use '*' to match any suffix characters: - // Find items starting with 'wri-'. + // Use '*' to match any characters after a prefix: + // Find items with a name that starts with 'wri'. "name TEXT $0", "wri*" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst index a2667eece5..92c1c2d89a 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst @@ -3,8 +3,8 @@ // Find projects with no complete items. "NONE items.isComplete == $0", true - // Find projects that contain an item with priority 10. - "ANY items.priority == $0", 10 + // Find projects that contain any item with priority 10. + "items.priority == $0", 10 // (ANY operator is implied.) // Find projects that only contain completed items. "ALL items.isComplete == $0", true @@ -13,5 +13,6 @@ // either Alex or Ali. "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" - // Projects with no items assigned to either Alex or Ali. + // Find projects with no items assigned to either + // Alex or Ali. "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst new file mode 100644 index 0000000000..200a1408d7 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst @@ -0,0 +1,12 @@ +.. code-block:: typescript + + // 1. Sorts by highest priority. + // 2. Returns the first item. + // 3. Remove duplicate names (N/A because a single + // item is always considered distinct). + "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" + + // 1. Removes any duplicates by name. + // 2. Sorts by highest priority. + // 3. Returns the first item. + "assignee == null DISTINCT(name) SORT(priority ASC) LIMIT(1)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst index 7ee32e3146..b4580eadc9 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst @@ -1,3 +1,12 @@ .. code-block:: typescript - "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" + // Find incomplete items, sort by `priority` + // in descending order, then sort equal `priority` + // values by `progressMinutes` in ascending order. + "isComplete == false SORT(priority DESC, progressMinutes ASC)" + + // Find high priority items, then remove from the results + // any items with duplicate `name` AND `assignee` values. + "priority >= 5 DISTINCT(name, assignee)" + // Find in-progress items, then return the first 10 results. + "progressMinutes > 0 && isComplete != true LIMIT(10)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst index 8effdea009..e1254e7ed6 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst @@ -1,9 +1,17 @@ .. code-block:: typescript - // Find projects whose name starts with the letter 'e' - // (case-insensitive). - "name BEGINSWITH[c] $0", "e" + // Find projects whose name starts with 'E' or 'e' + // (case-insensitive). + "name BEGINSWITH[c] $0", "E" - // Find projects whose name contains the letters 'ie' - // (case-sensitive). - "name CONTAINS $0", "ie" + // Find projects whose name contains 'ie' + // (case-sensitive). + "name CONTAINS $0", "ie" + + // Find items where the assignee name is lexicographically + // between 'Ali' and 'Chris' (case-sensitive). + "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" + + // Find projects where the street address is lexicographically + // greater than '123 Main St' (case-sensitive). + "projectLocation.address.street > $0", "123 Main St" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst deleted file mode 100644 index 51371a79fa..0000000000 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery-count.ts.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. code-block:: typescript - - // Find projects where the number of completed to-do items - // is greater than or equal to the project's `quota` property. - "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst index 9228876e1c..126129f7e2 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst @@ -1,4 +1,8 @@ .. code-block:: typescript - // Find projects with incomplete to-do items assigned to Alex. - "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" + // Find projects with incomplete items with 'Demo' in the name. + "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" + + // Find projects where the number of completed items + // is greater than or equal to the project's `quota` property. + "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst index 90a837faa8..fc9ad3f4df 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst @@ -1,5 +1,13 @@ .. code-block:: typescript - "mixedType.@type == 'string'" + // Find projects with an `additionalInfo` property of + // string type. + "additionalInfo.@type == 'string'" - "mixedType.@type == 'bool'" + // Find projects with an `additionalInfo` property of + // `collection` type, which matches list or dictionary types. + "additionalInfo.@type == 'collection'" + + // Find projects with an `additionalInfo` property of + // list type, where any list element is of type 'bool'. + "additionalInfo[*].@type == 'bool'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst deleted file mode 100644 index 1141952739..0000000000 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.uuid.ts.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. code-block:: typescript - - "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" diff --git a/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst b/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst index 57dfa8ba30..4c74ff4715 100644 --- a/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst +++ b/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst @@ -33,6 +33,7 @@ quota?: number; comments?: Realm.Dictionary; projectLocation?: Office; + additionalInfo!: Realm.Mixed; static schema: ObjectSchema = { name: "Project", @@ -43,6 +44,7 @@ quota: "int?", comments: "string?{}", projectLocation: "Office?", + additionalInfo: "mixed", }, primaryKey: "_id", }; diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index 6220062176..c5d461c791 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -7,7 +7,7 @@ Realm Query Language (RQL) .. meta:: :description: Use Realm Query Language (RQL) to retrieve objects from the database. - :keywords: Realm, Flutter SDK, Kotlin SDK, Java SDK, Node.js SDK, code example, filter, search + :keywords: Realm, Flutter SDK, Kotlin SDK, Java SDK, Node.js SDK, code example .. facet:: :name: genre @@ -25,48 +25,38 @@ Realm Query Language (RQL) .. tabs-selector:: drivers -Realm Query Language (RQL) is a string-based query language to constrain -searches when retrieving objects from a realm. SDK-specific methods pass queries -to the Realm query engine, which retrieves matching objects from the realm. -Realm Query Language syntax is based on `NSPredicate -`__. +Realm Query Language (RQL) is a string-based query language that you can use +to construct queries in most Atlas Device SDKs. The SDK-specific methods pass +the queries +to the Realm database query engine, which retrieves matching database objects. -Queries evaluate a predicate for every object in the collection being queried. -If the predicate resolves to ``true``, the results collection includes the object. +.. important:: Swift SDK Does Not Support Realm Query Language (RQL) -You can use Realm Query Language in most Realm SDKs with your SDK's filter -or query methods. The Swift SDK is the exception, as it uses the -:ref:`NSPredicate query API `. -Some SDKs also support idiomatic APIs for querying realms in their language. + The Swift SDK does *not* support querying with Realm Query Language. + Instead, it uses NSPredicate to query a database. For more information, refer to :ref:`Type-Safe and NSPredicate Queries (Swift SDK) `. -Query with Realm SDKs ---------------------- +With the exception of the Swift SDK, you can use Realm Query Language with your preferred SDK's filter +or query methods. For more information, refer to :ref:`sdks-crud-read`. -For language and SDK-specific methods for querying data, refer to the related -documentation: +The following SDKs also support language-specific idiomatic APIs for querying +databases: -- :ref:`sdks-crud-read` - :ref:`Fluent Interface (Java SDK) ` - :ref:`LINQ (.NET SDK) ` - :ref:`Type-Safe and NSPredicate Queries (Swift SDK) ` -.. note:: Swift SDK does not support Realm Query Language - - The Swift SDK does not support querying with Realm Query Language. - You can instead use NSPredicate to query Realm. For examples of querying - Realm in the Swift SDK, refer to :ref:`Filter Data - Swift SDK `. - You can also use Realm Query Language to browse for data in :ref:`Realm Studio `. Realm Studio is a visual tool -to view, edit, and design Realm files. +to view, edit, and design ``.realm`` database files. Examples on This Page --------------------- -Many of the examples in this page use a simple data set for a to-do list app. +Most of the examples on this page use a simple data set for a to-do list app +that include the following database objects: The two Realm object types are ``Project`` and ``Item``. -- An ``Item`` has a name, assignee's name, and completed flag. +- ``Item``: Each item object has a name, assignee's name, and completed flag. There is also an arbitrary number for priority (higher is more important) and a count of minutes spent working on it. - A ``Project`` has zero or more ``Items`` and an optional quota @@ -74,14 +64,16 @@ The two Realm object types are ``Project`` and ``Item``. See the schema for these two classes, ``Project`` and ``Item``, below: -.. include:: /includes/sdk-examples/crud/query/rql/rql-example-data-model.rst - +.. includes:: source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst Query Syntax ------------ -Expressions and Predicates -~~~~~~~~~~~~~~~~~~~~~~~~~~ +Realm Query Language syntax is based on `NSPredicate +`__. + +Queries evaluate a predicate for every object in the collection being queried. +If the predicate resolves to ``true``, the results collection includes the object. Realm Query Language uses expressions and predicates to evaluate queries. @@ -91,27 +83,38 @@ Realm Query Language uses expressions and predicates to evaluate queries. - **Predicates** are expressions that evaluate to ``true`` or ``false``. For example, ``name == 'Ali'`` is a predicate that evaluates to ``true`` if the name property is 'Ali'. + Realm Query Language also supports the following predicates: -TRUEPREDICATE and FALSEPREDICATE + - ``TRUEPREDICATE`` - Matches all objects. This is the default predicate. + - ``FALSEPREDICATE`` - Matches no objects. -Case Sensitivity -~~~~~~~~~~~~~~~~ -Unless otherwise noted, RQL operators and keywords are case insensitive. +.. _rql-parameterized-queries: -``[c]`` denotes case sensitivity in the following examples. +Parameterized vs. Serialized Queries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Dot & Bracket Notation -~~~~~~~~~~~~~~~~~~~~~~ +You can format queries in the following two ways: -.. TODO: confirm how we want to communicate which SDK versions support bracket notation +- **Serialized queries** pass values directly in the expression. -You can use **dot notation** or **bracket notation** to refer to child -properties of an object, including the properties of embedded objects and -relationships: + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst + +- **Parameterized queries** pass interpolated variables as additional + arguments. The syntax for interpolated variables is + ``$``, starting at ``0`` and incrementing for each additional variable. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst + +Unless otherwise noted, both formats are supported. + +Dot Notation +~~~~~~~~~~~~ .. TODO: add bracket notation to example +You can use **dot notation** to refer to child properties of an object, including the properties of embedded objects and relationships: + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst You can also chain these notations for nested properties. @@ -123,31 +126,10 @@ property ``address``. You can chain dot notations to query the deeply nested .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst - -.. _rql-parameterized-queries: - -Parameterized vs. Serialized Queries -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can format queries in two ways: - -- **Serialized queries** pass values directly in the expression. - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst - -- **Parameterized queries** pass interpolated variables as additional - arguments. The syntax for interpolated variables is - ``$``, starting at ``0`` and incrementing for each additional variable. - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst - -Supported Types -~~~~~~~~~~~~~~~ - .. _rql-nil-type: Nil Type -```````` +~~~~~~~~ Realm Query Language includes the ``nil`` type to represent a null pointer. You can either reference ``nil`` directly in your queries or with a parameterized query. @@ -156,11 +138,13 @@ to ``nil``. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst + .. _rql-operators: Operators --------- + .. _rql-comparison-operators: Comparison Operators @@ -168,35 +152,44 @@ Comparison Operators Use comparison operators to compare values of matching data types. -.. TODO: link or mention how ANY works (noted as equivalent to IN in this table) - .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator - Description - * - ``BETWEEN {N1, N2}`` - - Evaluates to ``true`` if the left-hand numerical or date expression - is between or equal to the right-hand range. For dates, this evaluates - to ``true`` if the left-hand date is within the right-hand date range. + * - ``BETWEEN {X, Y}`` + - Evaluates to ``true`` if the left-hand expression (``X``) + is between or equal to the right-hand expression (``Y``) range. + + - For dates, this evaluates to ``true`` if the left-hand date is within the right-hand date range. + - For strings, this evaluates to ``true`` if the left-hand string is + lexicographically within the right-hand range. * - | ``==``, ``=`` - Evaluates to ``true`` if the left-hand expression is equal to the right-hand expression. + - For strings, this evaluates to ``true`` if the left-hand string is + lexicographically equal to the right-hand string. + * - | ``>`` - Evaluates to ``true`` if the left-hand numerical or date expression is greater than the right-hand numerical or date expression. - For dates, this evaluates to ``true`` if the left-hand date is later - than the right-hand date. + + - For dates, this evaluates to ``true`` if the left-hand date is later + than the right-hand date. + - For strings, this evaluates to ``true`` if the left-hand string is + lexicographically greater than the right-hand string. * - | ``>=`` - - Evaluates to ``true`` if the left-hand numerical or date expression - is greater than or equal to the right-hand numerical or date expression. - For dates, this evaluates to ``true`` if the left-hand date is later than + - Evaluates to ``true`` if the left-hand expression + is greater than or equal to the right-hand expression. + + - For dates, this evaluates to ``true`` if the left-hand date is later than or the same as the right-hand date. + - For strings, this evaluates to ``true`` if the left-hand string is lexicographically greater than or equal to the right-hand string. * - | ``IN`` - Evaluates to ``true`` if the left-hand expression is in the @@ -206,20 +199,23 @@ Use comparison operators to compare values of matching data types. * - | ``<`` - Evaluates to ``true`` if the left-hand numerical or date expression is less than the right-hand numerical or date expression. - For dates, this evaluates to ``true`` if the left-hand date is earlier - than the right-hand date. + + - For dates, this evaluates to ``true`` if the left-hand date is earlier + than the right-hand date. + - For strings, this evaluates to ``true`` if the left-hand string is lexicographically less than the right-hand string. * - | ``<=`` - Evaluates to ``true`` if the left-hand numeric expression is less than - or equal to the right-hand numeric expression. For dates, this evaluates - to ``true`` if the left-hand date is earlier than or the same - as the right-hand date. + or equal to the right-hand numeric expression. + + - For dates, this evaluates to ``true`` if the left-hand date is earlier + than or the same as the right-hand date. + - For strings, this evaluates to ``true`` if the left-hand string is lexicographically less than or equal to the right-hand string. * - | ``!=``, ``<>`` - Evaluates to ``true`` if the left-hand expression is not equal to the right-hand expression. - The following example uses comparison operators to find to-do items whose property values match certain criteria: @@ -229,7 +225,7 @@ property values match certain criteria: The type on both sides of the operator must be equivalent. For example, comparing an ObjectId with string will result in a precondition - failure with a message like: + failure with a message similar to the following: .. code-block:: :copyable: false @@ -241,108 +237,34 @@ property values match certain criteria: including decimal, float, and Decimal128. -.. _rql-string-operators: - -String Operators -~~~~~~~~~~~~~~~~ - -Compare string values using these string operators. -Regex-like wildcards allow more flexibility in search. - -.. note:: - - You can use the following modifiers with the string operators: - - - ``[c]`` for case insensitivity. - - .. code-block:: javascript - - "name CONTAINS[c] $0", 'a' - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Operator - - Description - - * - | ``BEGINSWITH`` - - Evaluates to ``true`` if the left-hand string expression begins with - the right-hand string expression. This is similar to ``contains``, - but only matches if the right-hand string expression is found - at the beginning of the left-hand string expression. - - * - | ``CONTAINS`` - - Evaluates to ``true`` if the right-hand string expression - is found anywhere in the left-hand string expression. - - * - | ``ENDSWITH`` - - Evaluates to ``true`` if the left-hand string expression ends - with the right-hand string expression. This is similar to ``contains``, - but only matches if the left-hand string expression is found - at the very end of the right-hand string expression. - - * - | ``LIKE`` - - Evaluates to ``true`` if the left-hand string expression - matches the right-hand string wildcard string - expression. A wildcard string expression is a string - that uses normal characters with two special wildcard - characters: - - - The ``*`` wildcard matches zero or more of any character - - The ``?`` wildcard matches any character. - - For example, the wildcard string "d?g" matches "dog", - "dig", and "dug", but not "ding", "dg", or "a dog". - - * - | ``==``, ``=`` - - Evaluates to ``true`` if the left-hand string is lexicographically equal - to the right-hand string. - - * - | ``!=``, ``<>`` - - Evaluates to ``true`` if the left-hand string is not lexicographically - equal to the right-hand string. - -.. example:: - - We use the query engine's string operators to find: - - - Projects with a name starting with the letter 'e' - - Projects with names that contain 'ie' - - .. literalinclude:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.js - :language: javascript - .. _rql-logical-operators: Logical Operators ~~~~~~~~~~~~~~~~~ -Make compound predicates using logical operators. +Use logical operators to create compound predicates. .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator - Description - * - | ``AND`` - | ``&&`` + * - | ``AND`` | ``&&`` - Evaluates to ``true`` if both left-hand and right-hand expressions are ``true``. - * - | ``NOT`` - | ``!`` + * - | ``NOT`` | ``!`` - Negates the result of the given expression. - * - | ``OR`` - | ``||`` + * - | ``OR`` | ``||`` - Evaluates to ``true`` if either expression returns ``true``. The following example uses logical operators to combine multiple predicates: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst + .. _rql-arithmetic-operators: Arithmetic Operators @@ -353,7 +275,7 @@ evaluating numeric data types, including object properties. .. list-table:: :header-rows: 1 - :widths: 40 60 + :widths: 20 80 * - Operator - Description @@ -373,18 +295,17 @@ The following example uses arithmetic operators on Item object properties contai .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst + .. _rql-aggregate-operators: Aggregate Operators ~~~~~~~~~~~~~~~~~~~ -.. TODO: link to collection query section -Aggregate operators traverse a collection and reduce it to a single value. -You can use aggregate operators on collection properties, such as a list, or on +Use aggregate operators to traverse a collection and reduce it to a single value. .. list-table:: :header-rows: 1 - :widths: 40 60 + :widths: 20 80 * - Operator - Description @@ -409,12 +330,47 @@ You can use aggregate operators on collection properties, such as a list, or on - Evaluates to the sum of a given numerical property across a collection, excluding ``null`` values. - The following example uses aggregate operators to find projects whose ``items`` collection property meets certain criteria: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst + +.. _rql-collection-operators: + +Collection Operators +~~~~~~~~~~~~~~~~~~~~ + +A **collection operator** lets you query list properties within a collection of objects. +Collection operators filter a collection by applying a predicate +to every element of a given list property of the object. +If the predicate returns true, the object is included in the output collection. + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Operator + - Description + + * - ``ALL`` + - Returns objects where the predicate evaluates to ``true`` for all objects + in the collection. + + * - ``ANY``, ``SOME`` + - Returns objects where the predicate evaluates to ``true`` for any objects + in the collection. + + * - ``NONE`` + - Returns objects where the predicate evaluates to false for all objects + in the collection. + +The following example uses collection operators to find projects whose ``items`` +collection property meets certain criteria + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst + + .. _rql-sort-distinct-limit: Sort, Distinct, and Limit Operators @@ -460,9 +416,9 @@ shapes the returned results using sort, distinct, and limit operators: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst +Type-Specific Operators +----------------------- -Data Type Operators -------------------- .. _rql-type-operator: @@ -493,13 +449,417 @@ The following example uses the ``@type`` operator to find projects whose mixed data type ``additionalInfo`` property type matches specific criteria: -.. literalinclude:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.js - :language: js +.. include:: examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst + + +.. _rql-dictionary-operators: + +Dictionary Operators +~~~~~~~~~~~~~~~~~~~~ + +Use dictionary operators in combination with +:ref:`comparison operators ` to filter objects +based on dictionary keys and values. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Operator + - Description + + * - ``@values`` + - Returns objects that have a specified dictionary value. + + * - ``@keys`` + - Returns objects that have a specified dictionary key. + + * - ``@size``, ``@count`` + - The number of elements in a dictionary. + + * - ``Dictionary['key']`` + - The value of a dictionary key. + + * - ``ALL | ANY | NONE .@type`` + - Checks if the dictionary contains properties of certain type. + +The following example uses dictionary operators with comparison operators to find projects based on the ``comments`` dictionary property: + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst + + +.. _rql-string-operators: + +String Operators +~~~~~~~~~~~~~~~~ + +Use string operators or :ref:`comparison operators ` +to filter objects based on string values. SDKs evaluate string values +:wikipedia:`lexicographically `. + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Operator or Modifier + - Description + + * - | ``BEGINSWITH`` + - Evaluates to ``true`` if the left-hand string begins with + the right-hand string. This is similar to ``contains``, + but only matches if the right-hand string is found + at the beginning of the left-hand string. + + * - | ``CONTAINS`` + - Evaluates to ``true`` if the right-hand string + is found anywhere in the left-hand string. + + * - | ``ENDSWITH`` + - Evaluates to ``true`` if the left-hand string ends + with the right-hand string. This is similar to ``contains``, + but only matches if the left-hand string is found + at the very end of the right-hand string. + + * - | ``LIKE`` + - Evaluates to ``true`` if the left-hand string + matches the right-hand string wildcard string. A wildcard string expression is a string + that uses normal characters with two special wildcard + characters: + + - The ``*`` wildcard matches zero or more of any character + - The ``?`` wildcard matches any character. + + For example, the wildcard string "d?g" matches "dog", + "dig", and "dug", but not "ding", "dg", or "a dog". + + * - | ``[c]`` + - Modifier that indicates a string value is *not* case sensitive. + +The following example uses string and comparison operators to find projects +based on the project name: + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst + +.. tip:: String Values are Case Sensitive + + String values are case sensitive by default. Use the ``[c]`` modifier to specify that values are *not* case sensitive. + +Type-Specific Queries +--------------------- + + +.. _rql-list-queries: + +List Comparisons +~~~~~~~~~~~~~~~~ + +Use :ref:`comparison operators ` and +:ref:`collection operators ` to filter based +on lists of data. + +You can compare any type of valid list, including: + +- Collections of objects, which let you filter against other data + in the database. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst + +- Lists defined directly in the query, which let you filter against + static data. You define static lists as a comma-separated list of + literal values enclosed in opening (``{``) and closing (``}``) braces. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst + +- Native list objects passed in a :ref:`parameterized expression + `, which let you pass application data + directly to your queries. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst + +.. note:: Defaults to ``ANY`` + + If you do not define a collection operator, a list expression defaults + to the ``ANY`` operator. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst + +The following table demonstrates how collection operators interact with +lists and comparison operators: + +.. list-table:: + :widths: 45 10 45 + + * - Expression + - Match? + - Reason + + * - ``ANY {1, 2, 3} > ALL {1, 2}`` + - true + - A value on the left (3) is greater than some value on the right (both 1 and 2) + + * - ``ANY {1, 2, 3} == NONE {1, 2}`` + - true + - 3 does not match either of 1 or 2 + + * - ``ANY {4, 8} == ANY {5, 9, 11}`` + - false + - Neither 4 nor 8 matches any value on the right (5, 9 or 11) + + * - ``ANY {1, 2, 7} <= NONE {1, 2}`` + - true + - A value on the left (7) is not less than or equal to both 1 and 2 + + * - ``ALL {1, 2} IN ANY {1, 2, 3}`` + - true + - Every value on the left (1 and 2) is equal to 1, 2 or 3 + + * - ``ALL {3, 1, 4, 3} == NONE {1, 2}`` + - false + - 1 matches a value in the NONE list (1 or 2) + + * - ``ALL {} in ALL {1, 2}`` + - true + - An empty list matches all lists + + * - ``NONE {1, 2, 3, 12} > ALL {5, 9, 11}`` + - false + - 12 is bigger than all values on the right (5, 9, and 11) + + * - ``NONE {4, 8} > ALL {5, 9, 11}`` + - true + - 4 and 8 are both less than some value on the right (5, 9, or 11) + + * - ``NONE {0, 1} < NONE {1, 2}`` + - true + - 0 and 1 are both less than none of 1 and 2 + + +.. _rql-objectid-uuid-operators: + +ObjectId and UUID Comparisons +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use :ref:`comparison operators ` to compare :manual:`BSON ObjectIds ` and +:manual:`UUIDs ` for equality. These data types are +often used as primary keys. + +You can use pass ``ObjectId`` and ``UUID`` values either as parameterized query +arguments or to the ``oid()`` or ``uuid()`` predicate functions, respectively. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Operator + - Description + + * - | ``oid()`` + - The string representation of the ``ObjectID`` to evaluate. + + * - | ``uuid()`` + - The string representation of the ``UUID`` to evaluate. + +The following examples use equality comparison operators to find items based on their ``_id`` property: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst + +.. _rql-date-operators: + +Date Comparisons +~~~~~~~~~~~~~~~~ + +Use :ref:`comparison operators ` to query date types. + +Specify dates in the following formats: + +- As a date in UTC, with the date and time separated by ``@`` or ``T``: + ``YYYY-MM-DD@HH:mm:ss:nnnnnnnnnn`` + (year-month-day@hours:minutes:seconds:nanoseconds), UTC. +- As a time in seconds since the :wikipedia:`Unix epoch `: + ``Ts:n`` + (``T`` designates the start of the time, ``s`` is the number of seconds, and ``n`` is the number of nanoseconds). + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst + +The following example uses a parameterized query to find items based on a new ``dateCreated`` property that populates when an item is marked as complete: + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rest + +.. tip:: Parameterize Date Queries + + We recommend using a parameterized query to pass the date data type from the SDK language you are using to your query. + +.. _rql-backlinks: + +Backlink Queries +~~~~~~~~~~~~~~~~ + +A **backlink** is an :ref:`inverse relationship ` link that lets +you query objects that reference another object. Backlinks use the to-one and to-many +relationships defined in your object schemas but reverse the direction. +Every relationship that you define in your schema implicitly has a +corresponding backlink. + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Operator + - Description + + * - ``@links`` + - Accesses the backlink of a relationship specified by the object type and + property name (``@links..``). + * - ``@count`` + - The number of elements in a backlink collection. You can use the + ``@count`` operator directly on ``@links`` to query the count of all relationships that point to an object. + +You can access backlinks: + +- Using the ``@links..`` syntax, where + ```` and ```` refer to a specific property on an + object type that references the queried object type. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst + +- Using the ``linkingObjects`` property to explicitly include the backlink in your data model. This lets you reference the backlink through an assigned property name using :ref:`dot notation `. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst + +The result of a backlink is treated like a collection and supports +:ref:`collection operators ` and :ref:`aggregate operators `. + +The following examples find items based on the projects they belong to through the ``@links`` operator or the ``projects`` property: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst + +.. _rql-fts: + +Full Text Search (FTS) Queries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Perform boolean match word searches to query on properties that have a full-text +search (FTS) annotation. For information on enabling FTS on a property, refer to +:ref:`sdks-fts-property`. + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Operator + - Description + + * - ``TEXT`` + - Evaluates to ``true`` if the left-hand FTS-enabled string property + matches the right-hand string or wildcard string. A wildcard string expression is a string + that uses normal characters with two special wildcard + characters: + + - The ``*`` wildcard matches zero or more of any character that occur + after the string. + - The ``-`` wildcard matches all characters for exclusion from results. + +Query strings are converted to tokens by a tokenizer using the following rules: + +- Tokens can only consist of characters from ASCII and the Latin-1 supplement (western languages). All other characters are considered whitespace. +- Strings split by a hyphen (``-``) are split into two tokens. For example, ``full-text`` splits into ``full`` and ``text``. +- Tokens are diacritics insensitive and case insensitive. + +You can search for entire words or phrases, or limit your results with the +following wildcard characters: + +- Exclude results for a word by placing the ``-`` character in front of the word. +- Specify prefixes by placing the ``*`` wildcard at the end of a prefix. Suffix + searching is not currently supported. + +The following example uses the ``TEXT`` operator to find items based on their FTS-enabled +``name`` property: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst + +.. _rql-geospatial: + +Geospatial Queries +~~~~~~~~~~~~~~~~~~ + +Use the ``geoWithin`` operator to query geospatial data. For more information on +defining and working with geospatial data, refer to :ref:`sdks-define-geospatial-object`. + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Operator + - Description + + * - ``geoWithin`` + - Returns objects where the latitude/longitude pair in a custom embedded object's ``coordinates`` property + is contained within a specified geospatial shape. + The following geospatial shapes are supported: + + - ``GeoCircle`` + - ``GeoBox`` + - ``GeoPolygon`` + +The following example compares the coordinates of +the embedded ``location`` property against the boundaries of the ``GeoCircle`` +shape named +``smallCircle``: + +.. include:: /examples/generated/node/v12/geospatial.test.snippet.rql-geospatial.ts.rst + +.. important:: Geospatial Data Does Not Support Parameterized Queries + + You cannot use parameterized queries with geospatial data. + +.. _rql-subqueries: + +List Subqueries +~~~~~~~~~~~~~~~ + +Use the ``SUBQUERY()`` predicate function to iterate through list properties +with an additional query. Subqueries are useful when you need to match objects +in a list property based on multiple conditions. + +Subqueries use the following syntax: + +``SUBQUERY(, $, ).@count`` + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Operator + - Description + + * - ``SUBQUERY()`` + - Returns list objects for the specified collection where the predicate + evaluates to ``true``. Contains the following parameters: + + - ``collection``: The name of the list property to iterate through. + - ``variableName``: A variable name of the element to use in the + subquery, prefixed with ``$``. + - ``predicate``: The subquery predicate. Use the variable specified by ``variableName`` to refer to the currently-iterated element. + + * - ``@count`` + - The number of objects in the subquery results collection. This is + required for subquery filters. You can use the count of the subquery result as you would any other number in a valid expression. + +The following example uses subquery filters to find projects based on the +``items`` collection property using the ``$item`` variable name: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst + +.. tip:: Compare Count to ``0`` to Return All Matching Objects + The ``@count`` aggregate operator returns the number of objects in the + subquery results collection. You can compare the count with the number ``0`` to return all matching objects. -Data Type Queries ------------------ +.. _flexible-sync-rql-limitations: +Flexible Sync RQL Limitations +----------------------------- +.. include:: /includes/flex-sync-limitations.rst From 8f6922bb23aff96086ff0cd66598d2102b02fd46 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Fri, 31 May 2024 08:48:13 -0400 Subject: [PATCH 08/12] Fixing formatting --- .../v12/__tests__/models/rql-data-models.js | 54 ++ .../__tests__/realm-query-language.test.js | 487 ++++++++++-------- .../__tests__/realm-query-language.test.ts | 186 +++---- ...ge.test.snippet.aggregate-operators.ts.rst | 1 + ...ppet.backlinks-collection-operators.ts.rst | 12 +- ...st.snippet.backlinks-linkingObjects.ts.rst | 3 +- ...guage.test.snippet.basic-arithmetic.ts.rst | 1 + ...st.snippet.date-parameterized-query.ts.rst | 3 +- ...uage.test.snippet.deep-dot-notation.ts.rst | 3 +- ...e.test.snippet.dictionary-operators.ts.rst | 15 +- ...-language.test.snippet.dot-notation.ts.rst | 3 +- ...ippet.equivalent-lists-any-operator.ts.rst | 2 - ...snippet.list-comparisons-collection.ts.rst | 3 +- ...ppet.list-comparisons-parameterized.ts.rst | 3 +- ...est.snippet.list-comparisons-static.ts.rst | 3 +- ...uery-language.test.snippet.nil-type.ts.rst | 4 +- ...alm-query-language.test.snippet.oid.ts.rst | 13 +- ...ge.test.snippet.parameterized-query.ts.rst | 3 +- ...ery-language.test.snippet.predicate.ts.rst | 3 + ...language.test.snippet.set-operators.ts.rst | 6 +- ...t.sort-distinct-limit-order-matters.ts.rst | 3 +- ...ge.test.snippet.sort-distinct-limit.ts.rst | 10 +- ...guage.test.snippet.string-operators.ts.rst | 14 +- ...uery-language.test.snippet.subquery.ts.rst | 3 +- ...language.test.snippet.type-operator.ts.rst | 6 +- ...data-models.snippet.rql-data-models.js.rst | 33 ++ .../query-engines/realm-query-language.txt | 313 ++++++----- 27 files changed, 647 insertions(+), 543 deletions(-) create mode 100644 examples/node/v12/__tests__/models/rql-data-models.js create mode 100644 source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst diff --git a/examples/node/v12/__tests__/models/rql-data-models.js b/examples/node/v12/__tests__/models/rql-data-models.js new file mode 100644 index 0000000000..01f5d485f8 --- /dev/null +++ b/examples/node/v12/__tests__/models/rql-data-models.js @@ -0,0 +1,54 @@ +// Models for embedded objects & dot notation queries +const Address = { + name: "Address", + embedded: true, + properties: { + name: "string", + street: "string", + zipcode: "int", + }, +}; + +const Office = { + name: "Office", + properties: { + name: "string", + address: "Address", + }, +}; + +// :snippet-start: rql-data-models +const Item = { + name: "Item", + properties: { + _id: "objectId", + name: { type: "string", indexed: "full-text" }, + isComplete: { type: "bool", default: false }, + assignee: "string?", + priority: { type: "int", default: 0 }, + progressMinutes: { type: "int", default: 0 }, + projects: { + type: "linkingObjects", + objectType: "Project", + property: "items", + }, + }, + primaryKey: "_id", +}; + +const Project = { + name: "Project", + properties: { + _id: "objectId", + name: "string", + items: "Item[]", + quota: "int?", + comments: "string?{}", + projectLocation: "Office?", + additionalInfo: "mixed", + }, + primaryKey: "_id", +}; +// :snippet-end: + +export { Address, Item, Office, Project }; diff --git a/examples/node/v12/__tests__/realm-query-language.test.js b/examples/node/v12/__tests__/realm-query-language.test.js index 2ced76f64c..eadebe8baa 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.js +++ b/examples/node/v12/__tests__/realm-query-language.test.js @@ -2,7 +2,6 @@ import Realm, { BSON } from "realm"; import { Address, Item, Office, Project } from "./models/rql-data-models.ts"; import { describe, expect } from "@jest/globals"; -// Note: Snippets generated from TypeScript test file describe("Realm Query Language Reference", () => { let realm; const config = { schema: [Project, Item, Address, Office] }; @@ -17,7 +16,7 @@ describe("Realm Query Language Reference", () => { name: "Main Branch", address: { name: "Main Branch", - street: "123 Main St", + street: "999 Big Boulevard", zipcode: 10019, }, }; @@ -64,13 +63,16 @@ describe("Realm Query Language Reference", () => { }, ], quota: 1, // doesn't meet quota - comments: { - status: "Behind schedule", - projectNumber: 70150, - budget: 5000.0, - customerContact: ["Mina", "Devon"], - }, + comments: { status: "Behind schedule", projectNumber: "70150" }, projectLocation: mainBranch, + // Mixed property is of type dictionary of mixed values + // (date, list of strings, bool, and int) + additionalInfo: { + startDate: new Date("2021-01-01"), + customerContacts: ["Alice", "Bob"], + recurringCustomer: true, + budget: 10000, + }, }); const project = realm.create(Project, { _id: new BSON.ObjectId(), @@ -105,12 +107,10 @@ describe("Realm Query Language Reference", () => { }, ], quota: 1, // meets quota - comments: { - status: "Ahead of schedule", - projectNumber: 70187, - startDate: new Date("2021-01-01"), - }, + comments: { status: "Ahead of schedule", projectNumber: "70187" }, projectLocation: mainBranch, + // Mixed property is of type string + additionalInfo: "Customer is a VIP.", }); realm.create(Project, { @@ -129,13 +129,18 @@ describe("Realm Query Language Reference", () => { }, ], quota: 11, // doesn't meet quota - comments: { - status: "On track", - projectNumber: 4444, - startDate: new Date("2021-02-01"), - budget: 10000.0, - }, + comments: { status: "On track", projectNumber: "N/A" }, projectLocation: austinBranch, + // Mixed property is of type list, containing string and nested + // dictionary of mixed values (date, boolean, and int) + additionalInfo: [ + "Customer is difficult to work with.", + { + startDate: new Date("2021-03-01"), + recurringCustomer: false, + budget: 10000, + }, + ], }); }); }); @@ -176,6 +181,9 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); // [snippet-start] predicate const expression = "priority == 1"; + // Property Name: priority + // Operator: == + // Value: 1 // [snippet-end] expect(items.filtered(expression).length).toBe(1); }); @@ -195,6 +203,7 @@ describe("Realm Query Language Reference", () => { // [snippet-start] parameterized-query // Include one parameter with `$0`. "progressMinutes > 1 AND assignee == $0", "Ali" + // [remove-start] ); expect(substitution.length).toBe(1); @@ -205,9 +214,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const substitution = items.filtered( // [remove-end] - - // Include multiple parameters using ascending integers, - // starting at`$0`. + // Include multiple parameters using ascending integers, starting at`$0`. "progressMinutes > $0 AND assignee == $1", 1, "Alex" // [snippet-end] ); @@ -216,12 +223,20 @@ describe("Realm Query Language Reference", () => { test("Dot notation", () => { const address = realm.objects(Project); - const nestedMatch = address.filtered( + const nestedItem = address.filtered( + // [snippet-start] dot-notation + // Find projects whose `items` list property contains an item with a specific name. + "items[0].name == 'Approve project plan'" + // [snippet-end] + ); + const nestedZipcode = address.filtered( // [snippet-start] deep-dot-notation + // Find projects whose `projectLocation` property contains an embedded Address object with a specific zip code. "projectLocation.address.zipcode == 10019" // [snippet-end] ); - expect(nestedMatch.length).toBe(3); + expect(nestedItem.length).toBe(2); + expect(nestedZipcode.length).toBe(3); }); }); @@ -231,56 +246,37 @@ describe("Realm Query Language Reference", () => { const highPriorityItems = items.filtered( // [snippet-start] comparison-operators - // Find high-priority to-do items: - // Compare `priority` values against a threshold value, - // above which is considered high. - "priority > $0", - 5 - // [remove-start] - ); - expect(highPriorityItems.length).toBe(5); + // Compare `priority` values against a threshold value. + "priority > $0", 5 - const longRunningItems = items.filtered( - // [remove-end] - - // Find long-running to-do items: - // Compare `progressMinutes` values against a threshold value, - // where items at or above are considered long running. - "progressMinutes > $0", - 120 // [remove-start] ); - expect(longRunningItems.length).toBe(1); + expect(highPriorityItems.length).toBe(5); const unassignedItems = items.filtered( // [remove-end] - - // Find unassigned to-do items: // Compare `assignee` values to `null` value. "assignee == $0", null + // [remove-start] ); expect(unassignedItems.length).toBe(1); const progressMinutesRange = items.filtered( // [remove-end] - - // Find low-priority to-do items: // Compare `priority` values against an inclusive range of values. "priority BETWEEN { $0 , $1 }", 1, 5 + // [remove-start] ); expect(progressMinutesRange.length).toBe(2); const progressMinutesIn = items.filtered( - // [remove-end] - - // Find to-do items with specific progress times: + // [remove-end] // Compare `progressMinutes` values against any of the listed values. "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 // [snippet-end] ); - expect(progressMinutesIn.length).toBe(2); }); // prettier-ignore @@ -288,14 +284,14 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const aliComplete = items.filtered( // [snippet-start] logical-operators - // Find all to-do items assigned to Ali AND are completed. + // Find all items assigned to Ali AND marked completed. "assignee == $0 AND isComplete == $1", "Ali", true + // [remove-start] ); - const alexOrAli = items.filtered( // [remove-end] - // Find all to-do items assigned to Alex OR to Ali. + // Find all items assigned to Alex OR to Ali. "assignee == $0 OR assignee == $1", "Alex", "Ali" // [snippet-end] ); @@ -308,16 +304,17 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const basicMath = items.filtered( // [snippet-start] basic-arithmetic - "2 * priority > 6" + // Evaluate against an item's `priority` property value: + "2 * priority > 6" // resolves to `priority > 3` + // [remove-start] ); const lessBasicMath = items.filtered( // [remove-end] - // Is equivalent to - "priority >= 2 * (2 - 1) + 2" - // [snippet-end] - ); + "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` + // [remove-start] + ); expect(basicMath.length).toBe(6); expect(lessBasicMath.length).toBe(6); }); @@ -325,7 +322,8 @@ describe("Realm Query Language Reference", () => { test("Arithmetic with object properties", () => { const items = realm.objects(Item); const mathWithObjProps = items.filtered( - // [snippet-start] arithmetic-obj-properties + // [remove-end] + // Evaluate against multiple object property values: "progressMinutes * priority == 90" // [snippet-end] ); @@ -339,29 +337,49 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects(Project); const startWithE = projects.filtered( // [snippet-start] string-operators - // Find projects whose name starts with the letter 'e' - // (case-insensitive). - "name BEGINSWITH[c] $0", "e" + // Find projects whose name starts with 'E' or 'e' (case-insensitive). + "name BEGINSWITH[c] $0", "E" + // [remove-start] ); expect(startWithE.length).toBe(1); const containIe = projects.filtered( // [remove-end] - - // Find projects whose name contains the letters 'ie' - // (case-sensitive). + // Find projects whose name contains 'ie' (case-sensitive). "name CONTAINS $0", "ie" - // [snippet-end] + + // [remove-start] ); expect(containIe.length).toBe(0); }); + + test("String comparisons", () => { + const projects = realm.objects(Project); + const items = realm.objects(Item); + // prettier-ignore + const assigneeBetween = items.filtered( + // [remove-end] + // Find items where the assignee name is lexicographically between 'Ali' and 'Chris' (case-sensitive). + "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" + + // [remove-start] + ); + // prettier-ignore + const compareStreet = projects.filtered( + // [remove-end] + // Find projects where the street address is lexicographically greater than '123 Main St' (case-sensitive). + "projectLocation.address.street > $0", "123 Main St" + // [snippet-end] + ); + expect(compareStreet.length).toBe(2); + expect(assigneeBetween.length).toBe(2); + }); }); // prettier-ignore test("Aggregate queries", () => { const projects = realm.objects(Project); - // [snippet-start] aggregate-operators var priorityNum = 5; @@ -370,26 +388,25 @@ describe("Realm Query Language Reference", () => { // [remove-end] // Find projects with average item `priority` above 5. "items.@avg.priority > $0", priorityNum + // [remove-start] ); expect(averageItemPriorityAbove5.length).toBe(3); const allItemsLowerPriority = projects.filtered( // [remove-end] - - // Find projects with a maximum `priority` of 5 (all items must be less - // than 5). + // Find projects where maximum `priority` of all items is 5. "items.@max.priority < $0", priorityNum + // [remove-start] ); expect(allItemsLowerPriority.length).toBe(0); const allItemsHighPriority = projects.filtered( // [remove-end] - - // Find projects with a minimum `priority` of 5 (all items must be greater - // than 5). + // Find projects where minimum `priority` of all items is 5. "items.@min.priority > $0", priorityNum + // [remove-start] ); expect(allItemsHighPriority.length).toBe(0); @@ -399,13 +416,13 @@ describe("Realm Query Language Reference", () => { // Find projects with more than 5 items. "items.@count > $0", 5 + // [remove-start] ); expect(moreThan5Items.length).toBe(0); const longRunningProjects = projects.filtered( // [remove-end] - // Find projects with item `progressMinutes` greater than 100. "items.@sum.progressMinutes > $0", 100 // [snippet-end] @@ -413,50 +430,46 @@ describe("Realm Query Language Reference", () => { expect(longRunningProjects.length).toBe(1); }); - // prettier-ignore - describe("Collection queries", () => { - test("Collection operators", () => { + describe("Collection operators", () => { + test("Collection queries", () => { const projects = realm.objects(Project); + // prettier-ignore const noCompleteItems = projects.filtered( // [snippet-start] set-operators - // Projects with no complete items. - "NONE items.isComplete == $0", - true + // Find projects with no complete items. + "NONE items.isComplete == $0", true + // [remove-start] ); - + // prettier-ignore const anyTopPriorityItems = projects.filtered( // [remove-end] + // Find projects that contain any item with priority 10. + "items.priority == $0", 10 // (ANY operator is implied.) - // Projects that contain an item with priority 10. - "ANY items.priority == $0", - 10 // [remove-start] ); + // prettier-ignore const allItemsCompleted = projects.filtered( // [remove-end] + // Find projects that only contain completed items. + "ALL items.isComplete == $0", true - // Projects that only contain completed items. - "ALL items.isComplete == $0", - true // [remove-start] ); + // prettier-ignore const assignedToAlexOrAli = projects.filtered( // [remove-end] + // Find projects with at least one item assigned to either Alex or Ali. + "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" - // Projects with at least one item assigned to either Alex or Ali. - "ANY items.assignee IN { $0 , $1 }", - "Alex", - "Ali" // [remove-start] ); + // prettier-ignore const notAssignedToAlexOrAli = projects.filtered( // [remove-end] - - // Projects with no items assigned to either Alex or Ali. - "NONE items.assignee IN { $0 , $1 }", - "Alex", - "Ali" + // Find projects with no items assigned to either Alex or Ali. + "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" // [snippet-end] ); expect(noCompleteItems.length).toBe(1); @@ -473,11 +486,13 @@ describe("Realm Query Language Reference", () => { const collectionQuery = projects.filtered( // [snippet-start] list-comparisons-collection + // Find an item with the specified ObjectId value in the `items` collection. "oid(631a072f75120729dc9223d9) IN items._id" // [snippet-end] ); const staticQuery = items.filtered( // [snippet-start] list-comparisons-static + // Find items with a priority value matching any value in the static list. "priority IN {0, 1, 2}" // [snippet-end] ); @@ -487,9 +502,26 @@ describe("Realm Query Language Reference", () => { new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; + // Find items with an ObjectId value matching any value in the parameterized list. const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); // [snippet-end] + // prettier-ignore + const anyOperator = items.filtered( + // [snippet-start] equivalent-lists-any-operator + "assignee == ANY { $0, $1 }", "Alex", "Ali" + + // [remove-start] + ); + // prettier-ignore + const equivalentAnyOperator = items.filtered( + // [remove-end] + "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) + // [snippet-end] + ); + + expect(anyOperator.length).toBe(2); + expect(equivalentAnyOperator.length).toBe(2); expect(collectionQuery.length).toBe(1); expect(staticQuery.length).toBe(1); expect(parameterizedQuery.length).toBe(3); @@ -498,32 +530,70 @@ describe("Realm Query Language Reference", () => { test("Sort, distinct, and limit results", () => { const items = realm.objects(Item); - const sortedUniqueAliItems = items.filtered( + const sortedItems = items.filtered( // [snippet-start] sort-distinct-limit - "assignee == 'Ali' SORT(priority DESC) DISTINCT(name) LIMIT(5)" + // Find incomplete items, sort by `priority` in descending order, then + // sort equal `priority` values by `progressMinutes` in ascending order. + "isComplete == false SORT(priority DESC, progressMinutes ASC)" + + // [remove-start] + ); + expect(sortedItems[0].name).toBe("Demo template app"); + const distinctItems = items.filtered( + // [remove-end] + // Find high priority items, then remove from the results any items + // with duplicate values for both `name` AND `assignee` properties. + "priority >= 5 DISTINCT(name, assignee)" + + // [remove-start] + ); + expect(distinctItems.length).toBe(6); + const limitItems = items.filtered( + // [remove-end] + // Find in-progress items, then return the first 10 results. + "progressMinutes > 0 && isComplete != true LIMIT(10)" + // [snippet-end] + ); + expect(limitItems[0].name).toBe("Write tests"); + + const sortFirst = items.filtered( + // [snippet-start] sort-distinct-limit-order-matters + // 1. Sorts by highest priority. + // 2. Returns the first item. + // 3. Remove duplicate names (N/A because a single item is always considered distinct). + "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" + + // [remove-start] + ); + const limitLast = items.filtered( + // [remove-end] + // 1. Removes any duplicates by name. + // 2. Sorts by highest priority. + // 3. Returns the first item. + "assignee == null DISTINCT(name) SORT(priority ASC) LIMIT(1)" // [snippet-end] ); - expect(sortedUniqueAliItems.length).toBe(1); }); - test("Subquery queries", () => { + test("Subquery query", () => { const projects = realm.objects(Project); const subquery = projects.filtered( // [snippet-start] subquery - // Find projects with incomplete to-do items assigned to Alex. - "SUBQUERY(items, $item, $item.isComplete == false AND $item.assignee == 'Alex').@count > 0" - // [snippet-end] + // Find projects with incomplete items with 'Demo' in the name. + "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" + + // [remove-start] ); expect(subquery.length).toBe(1); - expect(subquery[0].name).toBe("Example Project with Items"); + expect(subquery[0].name).toBe("Project that Meets Quota"); const subquery2 = projects.filtered( - // [snippet-start] subquery-count - // Find projects where the number of completed to-do items - // is greater than or equal to the project's `quota` property. + // [remove-end] + // Find projects where the number of completed items is greater than or equal to the project's `quota` property. "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" // [snippet-end] ); + expect(subquery2.length).toBe(1); expect(subquery2[0].name).toBe("Project that Meets Quota"); }); @@ -531,69 +601,46 @@ describe("Realm Query Language Reference", () => { // prettier-ignore test("Dictionary operators", () => { const dictionaries = realm.objects(Project); - const statusKey = dictionaries.filtered( // [snippet-start] dictionary-operators - // Finds `comments` dictionary properties with key 'status' + // Find projects whose `comments` dictionary property have a key of 'status'. "comments.@keys == $0", "status" // [remove-start] ); const statusOnTrack = dictionaries.filtered( // [remove-end] - // Find `comments` dictionary properties with key 'status' - // and value 'On track' - "comments['status'] == $0", "On track" + // Find projects whose `comments` dictionary property have a 'status' key with a value that ends in 'track'. + "comments['status'] LIKE $0", "*track" + // [remove-start] ); const numItemsInDict = dictionaries.filtered( // [remove-end] - // Finds `comments` dictionary properties with - // more than one key-value pair + // Find projects whose `comments` dictionary property have more than one key-value pair. "comments.@count > $0", 1 // [remove-start] ); - const hasString = dictionaries.filtered( - // [remove-end] - //Find `comments` dictionary properties where ANY - // values are of type 'string` - "ANY comments.@type == 'string'" - // [remove-start] - ); - - const hasStringImplied = dictionaries.filtered( + const allString = dictionaries.filtered( // [remove-end] - "comments.@type == 'string'" // (Equivalent - ANY is implied.) - - // [remove-start] - ); - - const allInt = dictionaries.filtered( - // [remove-end] - // Finds `comments` dictionary properties where ALL - // values are of type 'int' - "ALL comments.@type == 'int'" + // Find projects whose `comments` dictionary property contains only values of type 'string'. + "ALL comments.@type == 'string'" // [remove-start] ); const noInts = dictionaries.filtered( // [remove-end] - // Finds `comments` dictionary properties where NO - // values are of type 'int' + // Find projects whose `comments` dictionary property contains no values of type 'int'. "NONE comments.@type == 'int'" - - // [remove-start] + // [snippet-end] ); - expect(statusKey.length).toBe(3); expect(statusOnTrack.length).toBe(1); expect(numItemsInDict.length).toBe(3); - expect(hasString.length).toBe(3); - expect(hasStringImplied.length).toBe(3); - expect(allInt.length).toBe(0); + expect(allString.length).toBe(3); expect(noInts.length).toBe(3); }); }); @@ -602,7 +649,8 @@ describe("Realm Query Language Reference", () => { test("Backlinks query @links", () => { const atLinksResult = realm.objects(Item).filtered( // [snippet-start] backlinks-atLinks - // Find items that belong to a project with a quota less than 10 (@links) + // Find items that belong to a project with a quota less than 10 + // (using '@links..'). "@links.Project.items.quota < 10" // [snippet-end] ); @@ -610,7 +658,8 @@ describe("Realm Query Language Reference", () => { const linkingObjectsResult = realm.objects(Item).filtered( // [snippet-start] backlinks-linkingObjects - // Find items that belong to a project with a quota greater than 10 (LinkingObjects) + // Find items that belong to a project with a quota greater than 10 through the Item object's `projects` property + // (using 'LinkingObjects'). "projects.quota > 10" // [snippet-end] ); @@ -620,27 +669,29 @@ describe("Realm Query Language Reference", () => { test("Backlinks collection operators", () => { const anyResult = realm.objects(Item).filtered( // [snippet-start] backlinks-collection-operators - // Find items where any project that references the item has a quota greater than 10. - "ANY @links.Project.items.quota > 10" + // Find items where no project that references the item has a quota greater than 10. + "NONE @links.Project.items.quota > 10" + // [remove-start] ); - expect(anyResult.length).toBe(2); + expect(anyResult.length).toBe(5); const allResult = realm.objects(Item).filtered( // [remove-end] - // Find items where all projects that reference the item have a quota - // less than 5. + // Find items where all projects that reference the item have a quota less than 5. "ALL @links.Project.items.quota < 5" - // [snippet-end] + + // [remove-start] ); expect(allResult.length).toBe(5); }); test("Backlinks aggregate operators", () => { const shallowResultLinkingObjects = realm.objects(Item).filtered( - // [snippet-start] backlinks-aggregate-operators - // Find items that are referenced by multiple projects + // [remove-end] + // Find items that are referenced by multiple projects. "projects.@count > 1" + // [remove-start] ); expect(shallowResultLinkingObjects.length).toBe(1); @@ -648,8 +699,9 @@ describe("Realm Query Language Reference", () => { const shallowResultAtLinks = realm.objects(Item).filtered( // [remove-end] - // Find items that are not referenced by any project + // Find items that are not referenced by any project. "@links.Project.items.@count == 0" + // [remove-start] ); expect(shallowResultAtLinks.length).toBe(1); @@ -657,10 +709,10 @@ describe("Realm Query Language Reference", () => { const deepResultAtLinks = realm.objects(Item).filtered( // [remove-end] - // Find items that belong to a project where the average item has - // been worked on for at least 5 minutes + // Find items that belong to a project where the average item has been worked on for at least 10 minutes "@links.Project.items.items.@avg.progressMinutes > 10" - // [snippet-end] + + // [remove-start] ); expect(deepResultAtLinks.length).toBe(2); expect(deepResultAtLinks[0].name).toBe("Write tests"); @@ -668,8 +720,8 @@ describe("Realm Query Language Reference", () => { test("Count all backlinks (@links.@count)", () => { const result = realm.objects(Item).filtered( - // [snippet-start] backlinks-atCount - // Find items that are not referenced by another object of any type + // [remove-end] + // Find items that are not referenced by another object of any type (backlink count is 0). "@links.@count == 0" // [snippet-end] ); @@ -678,54 +730,28 @@ describe("Realm Query Language Reference", () => { }); }); - describe("Type operator", () => { - // Uses a test-specific schema with mixed type - // TODO: Update main schema with mixed type property once collections-in-mixed is supported - const Mixed = { - name: "Mixed", - properties: { name: "string", mixedType: "mixed" }, - }; - let realm; - const path = "mixed.realm"; - - // Add, then delete objects for this test - beforeEach(async () => { - realm = await Realm.open({ - schema: [Mixed], - path, - }); - realm.write(() => { - realm.create("Mixed", { - name: "Marge", - mixedType: true, - }); - realm.create("Mixed", { - name: "Lisa", - mixedType: 22, - }); - realm.create("Mixed", { - name: "Bart", - mixedType: "carrumba", - }); - }); - }); - - afterEach(() => { - realm.close(); - Realm.deleteFile({ path }); - }); - + describe("Type operators", () => { test("Type operator", () => { - const mixed = realm.objects("Mixed"); - const mixedString = mixed.filtered( + const projects = realm.objects(Project); + const mixedString = projects.filtered( // [snippet-start] type-operator - "mixedType.@type == 'string'" + // Find projects with an `additionalInfo` property of string type. + "additionalInfo.@type == 'string'" + // [remove-start] ); - const mixedBool = mixed.filtered( + const mixedCollection = projects.filtered( // [remove-end] + // Find projects with an `additionalInfo` property of + // `collection` type, which matches list or dictionary types. + "additionalInfo.@type == 'collection'" - "mixedType.@type == 'bool'" + // [remove-start] + ); + const mixedBool = projects.filtered( + // [remove-end] + // Find projects with an `additionalInfo` property of list type, where any list element is of type 'bool'. + "additionalInfo[*].@type == 'bool'" // [snippet-end] ); expect(mixedString.length).toBe(1); @@ -733,22 +759,19 @@ describe("Realm Query Language Reference", () => { }); }); - // prettier-ignore test("Nil type", () => { const items = realm.objects(Item); const res = items.filtered( // [snippet-start] nil-type "assignee == nil" - // [snippet-end] + // [remove-start] ); - + // prettier-ignore const res2 = realm.objects(Item).filtered( - // [snippet-start] nil-type-parameterized-query - // comparison to language null pointer - "assignee == $0", null + // [remove-end] + "assignee == $0", null // 'null' maps to the SDK language's null pointer // [snippet-end] ); - expect(res.length).toBe(1); expect(res2.length).toBe(1); }); @@ -766,14 +789,14 @@ describe("Realm Query Language Reference", () => { const oidValueString = "6001c033600510df3bbfd864"; const uuid1String = "d1b186e1-e9e0-4768-a1a7-c492519d47ee"; const oidValue = new BSON.ObjectId(oidValueString); - const uuid1 = new BSON.UUID(uuid1String); + const uuidValue = new BSON.UUID(uuid1String); // Add, then delete objects for this test beforeEach(async () => { realm = await Realm.open({ schema: [OidUuid], path }); const obj1 = { _id: oidValue, - id: uuid1, + id: uuidValue, }; const obj2 = { _id: new BSON.ObjectId(), @@ -790,32 +813,45 @@ describe("Realm Query Language Reference", () => { Realm.deleteFile({ path }); }); - // prettier-ignore - test("ObjectId Operator", () => { + test("ObjectId query", () => { const oidUuids = realm.objects("OidUuid"); + // prettier-ignore const oidStringLiteral = oidUuids.filtered( // [snippet-start] oid + // Find an item whose `_id` matches the ObjectID value passed to 'oid()'. "_id == oid(6001c033600510df3bbfd864)" - // [snippet-end] + + // [remove-start] ); + const oidInterpolation = oidUuids.filtered( - // [snippet-start]oid-literal - "_id == $0", oidValue - // [snippet-end] + // [remove-end] + // Find an item whose `_id` matches the ObjectID passed as a parameterized query argument. + "_id == $0", + oidValue + + // [remove-start] ); expect(oidStringLiteral.length).toBe(1); expect(oidInterpolation.length).toBe(1); }); - - test("UUID Operator", () => { + test("UUID query", () => { const oidUuids = realm.objects("OidUuid"); const uuid = oidUuids.filtered( - // [snippet-start] uuid + // [remove-end] + // Find an item whose `id` matches the UUID value passed to 'uuid()'. "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" + + // [remove-start] + ); + // prettier-ignore + const test = oidUuids.filtered( + // [remove-end] + // Find an item whose `_id` matches the UUID passed as a parameterized query argument. + "id == $0", uuidValue // [snippet-end] ); - expect(uuid.length).toBe(1); }); }); @@ -862,9 +898,9 @@ describe("Realm Query Language Reference", () => { test("Date queries", () => { const dates = realm.objects("Date"); // [snippet-start] date-alt-representation - var today = new Date("April 01, 2021 03:24:00"); - - var thisYear = new Date("2021-01-01@17:30:15:0"); + var lastYear = new Date(1577883184000); // Unix timestamp in ms + var thisYear = new Date("2021-01-01@17:30:15:0"); // DateTime in UTC + var today = new Date("April 01, 2021 03:24:00"); // Alternate DateTime format // [snippet-end] const dateParameterizedQuery = dates.filtered( // [snippet-start] date-parameterized-query @@ -876,7 +912,7 @@ describe("Realm Query Language Reference", () => { const dateAlt1 = dates.filtered( // [remove-end] - // Find to-do items completed this year up to today. + // Find to-do items completed between the start of the year until today. "dateCompleted > $0 AND dateCompleted < $1", thisYear, today // [snippet-end] ); @@ -892,7 +928,7 @@ describe("Realm Query Language Reference", () => { const itemsWithWrite = items.filtered( // [snippet-start] rql-fts - // Filter for items with 'write' in the name + // Find items with 'write' in the name. "name TEXT $0", "write" // [remove-start] @@ -900,7 +936,8 @@ describe("Realm Query Language Reference", () => { const itemsWithWriteNotTest = items.filtered( // [remove-end] - // Find items with 'write' but not 'tests' using '-' + // Use '-' to exclude: + // Find items with 'write' but not 'tests' in the name. "name TEXT $0", "write -tests" // [remove-start] @@ -908,11 +945,11 @@ describe("Realm Query Language Reference", () => { const itemsStartingWithWri = items.filtered( // [remove-end] - // Find items starting with 'wri-' using '*' + // Use '*' to match any characters after a prefix: + // Find items with a name that starts with 'wri'. "name TEXT $0", "wri*" // [snippet-end] ); - expect(itemsWithWrite.length).toBe(2); expect(itemsWithWriteNotTest.length).toBe(0); expect(itemsStartingWithWri.length).toBe(2); diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts index d8d0bca06d..4b56fcfe0e 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.ts +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -181,6 +181,9 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); // :snippet-start: predicate const expression = "priority == 1"; + // Property Name: priority + // Operator: == + // Value: 1 // :snippet-end: expect(items.filtered(expression).length).toBe(1); }); @@ -200,6 +203,7 @@ describe("Realm Query Language Reference", () => { // :snippet-start: parameterized-query // Include one parameter with `$0`. "progressMinutes > 1 AND assignee == $0", "Ali" + // :remove-start: ); expect(substitution.length).toBe(1); @@ -210,9 +214,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const substitution = items.filtered( // :remove-end: - - // Include multiple parameters using ascending integers, - // starting at`$0`. + // Include multiple parameters using ascending integers, starting at`$0`. "progressMinutes > $0 AND assignee == $1", 1, "Alex" // :snippet-end: ); @@ -223,15 +225,13 @@ describe("Realm Query Language Reference", () => { const address = realm.objects(Project); const nestedItem = address.filtered( // :snippet-start: dot-notation - // Find projects whose `items` list property contains - // an Item object with a specific name. + // Find projects whose `items` list property contains an item with a specific name. "items[0].name == 'Approve project plan'" // :snippet-end: ); const nestedZipcode = address.filtered( // :snippet-start: deep-dot-notation - // Find projects whose `projectLocation` property contains - // an embedded Address object with a specific zip code. + // Find projects whose `projectLocation` property contains an embedded Address object with a specific zip code. "projectLocation.address.zipcode == 10019" // :snippet-end: ); @@ -248,31 +248,31 @@ describe("Realm Query Language Reference", () => { // :snippet-start: comparison-operators // Compare `priority` values against a threshold value. "priority > $0", 5 + // :remove-start: ); expect(highPriorityItems.length).toBe(5); const unassignedItems = items.filtered( // :remove-end: - // Compare `assignee` values to `null` value. "assignee == $0", null + // :remove-start: ); expect(unassignedItems.length).toBe(1); const progressMinutesRange = items.filtered( // :remove-end: - // Compare `priority` values against an inclusive range of values. "priority BETWEEN { $0 , $1 }", 1, 5 + // :remove-start: ); expect(progressMinutesRange.length).toBe(2); const progressMinutesIn = items.filtered( // :remove-end: - // Compare `progressMinutes` values against any of the listed values. "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 // :snippet-end: @@ -286,11 +286,11 @@ describe("Realm Query Language Reference", () => { // :snippet-start: logical-operators // Find all items assigned to Ali AND marked completed. "assignee == $0 AND isComplete == $1", "Ali", true + // :remove-start: ); const alexOrAli = items.filtered( // :remove-end: - // Find all items assigned to Alex OR to Ali. "assignee == $0 OR assignee == $1", "Alex", "Ali" // :snippet-end: @@ -306,11 +306,13 @@ describe("Realm Query Language Reference", () => { // :snippet-start: basic-arithmetic // Evaluate against an item's `priority` property value: "2 * priority > 6" // resolves to `priority > 3` + // :remove-start: ); const lessBasicMath = items.filtered( // :remove-end: "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` + // :remove-start: ); expect(basicMath.length).toBe(6); @@ -321,7 +323,6 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const mathWithObjProps = items.filtered( // :remove-end: - // Evaluate against multiple object property values: "progressMinutes * priority == 90" // :snippet-end: @@ -336,19 +337,18 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects(Project); const startWithE = projects.filtered( // :snippet-start: string-operators - // Find projects whose name starts with 'E' or 'e' - // (case-insensitive). + // Find projects whose name starts with 'E' or 'e' (case-insensitive). "name BEGINSWITH[c] $0", "E" + // :remove-start: ); expect(startWithE.length).toBe(1); const containIe = projects.filtered( // :remove-end: - - // Find projects whose name contains 'ie' - // (case-sensitive). + // Find projects whose name contains 'ie' (case-sensitive). "name CONTAINS $0", "ie" + // :remove-start: ); expect(containIe.length).toBe(0); @@ -360,22 +360,18 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const assigneeBetween = items.filtered( // :remove-end: - - // Find items where the assignee name is lexicographically - // between 'Ali' and 'Chris' (case-sensitive). + // Find items where the assignee name is lexicographically between 'Ali' and 'Chris' (case-sensitive). "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" + // :remove-start: ); // prettier-ignore const compareStreet = projects.filtered( // :remove-end: - - // Find projects where the street address is lexicographically - // greater than '123 Main St' (case-sensitive). + // Find projects where the street address is lexicographically greater than '123 Main St' (case-sensitive). "projectLocation.address.street > $0", "123 Main St" // :snippet-end: ); - expect(compareStreet.length).toBe(2); expect(assigneeBetween.length).toBe(2); }); @@ -392,24 +388,25 @@ describe("Realm Query Language Reference", () => { // :remove-end: // Find projects with average item `priority` above 5. "items.@avg.priority > $0", priorityNum + // :remove-start: ); expect(averageItemPriorityAbove5.length).toBe(3); const allItemsLowerPriority = projects.filtered( // :remove-end: - // Find projects where maximum `priority` of all items is 5. "items.@max.priority < $0", priorityNum + // :remove-start: ); expect(allItemsLowerPriority.length).toBe(0); const allItemsHighPriority = projects.filtered( // :remove-end: - // Find projects where minimum `priority` of all items is 5. "items.@min.priority > $0", priorityNum + // :remove-start: ); expect(allItemsHighPriority.length).toBe(0); @@ -419,13 +416,13 @@ describe("Realm Query Language Reference", () => { // Find projects with more than 5 items. "items.@count > $0", 5 + // :remove-start: ); expect(moreThan5Items.length).toBe(0); const longRunningProjects = projects.filtered( // :remove-end: - // Find projects with item `progressMinutes` greater than 100. "items.@sum.progressMinutes > $0", 100 // :snippet-end: @@ -441,39 +438,37 @@ describe("Realm Query Language Reference", () => { // :snippet-start: set-operators // Find projects with no complete items. "NONE items.isComplete == $0", true + // :remove-start: ); // prettier-ignore const anyTopPriorityItems = projects.filtered( // :remove-end: - // Find projects that contain any item with priority 10. "items.priority == $0", 10 // (ANY operator is implied.) + // :remove-start: ); // prettier-ignore const allItemsCompleted = projects.filtered( // :remove-end: - // Find projects that only contain completed items. "ALL items.isComplete == $0", true + // :remove-start: ); // prettier-ignore const assignedToAlexOrAli = projects.filtered( // :remove-end: - - // Find projects with at least one item assigned to - // either Alex or Ali. + // Find projects with at least one item assigned to either Alex or Ali. "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" + // :remove-start: ); // prettier-ignore const notAssignedToAlexOrAli = projects.filtered( // :remove-end: - - // Find projects with no items assigned to either - // Alex or Ali. + // Find projects with no items assigned to either Alex or Ali. "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" // :snippet-end: ); @@ -491,15 +486,13 @@ describe("Realm Query Language Reference", () => { const collectionQuery = projects.filtered( // :snippet-start: list-comparisons-collection - // Find an item with the specified ObjectId value - // in the `items` collection. + // Find an item with the specified ObjectId value in the `items` collection. "oid(631a072f75120729dc9223d9) IN items._id" // :snippet-end: ); const staticQuery = items.filtered( // :snippet-start: list-comparisons-static - // Find items with a priority value matching - // any value in the static list. + // Find items with a priority value matching any value in the static list. "priority IN {0, 1, 2}" // :snippet-end: ); @@ -509,8 +502,7 @@ describe("Realm Query Language Reference", () => { new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; - // Find items with an ObjectId value matching any value in the - // parameterized list. + // Find items with an ObjectId value matching any value in the parameterized list. const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); // :snippet-end: @@ -518,19 +510,13 @@ describe("Realm Query Language Reference", () => { const anyOperator = items.filtered( // :snippet-start: equivalent-lists-any-operator "assignee == ANY { $0, $1 }", "Alex", "Ali" + // :remove-start: ); // prettier-ignore const equivalentAnyOperator = items.filtered( // :remove-end: - "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) - // :remove-start: - ); - const equivalentNoneOperator = items.filtered( - // :remove-end: - - "assignee NONE { 'Alex', 'Ali' }" // Equivalent to != ANY. // :snippet-end: ); @@ -543,23 +529,22 @@ describe("Realm Query Language Reference", () => { test("Sort, distinct, and limit results", () => { const items = realm.objects(Item); - const projects = realm.objects(Project); const sortedItems = items.filtered( // :snippet-start: sort-distinct-limit - // Find incomplete items, sort by `priority` - // in descending order, then sort equal `priority` - // values by `progressMinutes` in ascending order. + // Find incomplete items, sort by `priority` in descending order, then + // sort equal `priority` values by `progressMinutes` in ascending order. "isComplete == false SORT(priority DESC, progressMinutes ASC)" + // :remove-start: ); expect(sortedItems[0].name).toBe("Demo template app"); const distinctItems = items.filtered( // :remove-end: - - // Find high priority items, then remove from the results - // any items with duplicate `name` AND `assignee` values. + // Find high priority items, then remove from the results any items + // with duplicate values for both `name` AND `assignee` properties. "priority >= 5 DISTINCT(name, assignee)" + // :remove-start: ); expect(distinctItems.length).toBe(6); @@ -570,18 +555,18 @@ describe("Realm Query Language Reference", () => { // :snippet-end: ); expect(limitItems[0].name).toBe("Write tests"); + const sortFirst = items.filtered( // :snippet-start: sort-distinct-limit-order-matters // 1. Sorts by highest priority. // 2. Returns the first item. - // 3. Remove duplicate names (N/A because a single - // item is always considered distinct). + // 3. Remove duplicate names (N/A because a single item is always considered distinct). "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" + // :remove-start: ); const limitLast = items.filtered( // :remove-end: - // 1. Removes any duplicates by name. // 2. Sorts by highest priority. // 3. Returns the first item. @@ -596,6 +581,7 @@ describe("Realm Query Language Reference", () => { // :snippet-start: subquery // Find projects with incomplete items with 'Demo' in the name. "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" + // :remove-start: ); expect(subquery.length).toBe(1); @@ -603,9 +589,7 @@ describe("Realm Query Language Reference", () => { const subquery2 = projects.filtered( // :remove-end: - - // Find projects where the number of completed items - // is greater than or equal to the project's `quota` property. + // Find projects where the number of completed items is greater than or equal to the project's `quota` property. "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" // :snippet-end: ); @@ -619,24 +603,21 @@ describe("Realm Query Language Reference", () => { const dictionaries = realm.objects(Project); const statusKey = dictionaries.filtered( // :snippet-start: dictionary-operators - // Find projects whose `comments` dictionary property - // have a key of 'status'. + // Find projects whose `comments` dictionary property have a key of 'status'. "comments.@keys == $0", "status" // :remove-start: ); const statusOnTrack = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property - // have a 'status' key with a value that ends in 'track'. + // Find projects whose `comments` dictionary property have a 'status' key with a value that ends in 'track'. "comments['status'] LIKE $0", "*track" // :remove-start: ); const numItemsInDict = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property - // have more than one key-value pair. + // Find projects whose `comments` dictionary property have more than one key-value pair. "comments.@count > $0", 1 // :remove-start: @@ -644,8 +625,7 @@ describe("Realm Query Language Reference", () => { const allString = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property - // contains only values of type 'string'. + // Find projects whose `comments` dictionary property contains only values of type 'string'. "ALL comments.@type == 'string'" // :remove-start: @@ -653,12 +633,10 @@ describe("Realm Query Language Reference", () => { const noInts = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property - // contains no values of type 'int'. + // Find projects whose `comments` dictionary property contains no values of type 'int'. "NONE comments.@type == 'int'" // :snippet-end: ); - expect(statusKey.length).toBe(3); expect(statusOnTrack.length).toBe(1); expect(numItemsInDict.length).toBe(3); @@ -680,8 +658,7 @@ describe("Realm Query Language Reference", () => { const linkingObjectsResult = realm.objects(Item).filtered( // :snippet-start: backlinks-linkingObjects - // Find items that belong to a project with a quota greater than 10 - // through the Item object's `projects` property + // Find items that belong to a project with a quota greater than 10 through the Item object's `projects` property // (using 'LinkingObjects'). "projects.quota > 10" // :snippet-end: @@ -692,21 +669,19 @@ describe("Realm Query Language Reference", () => { test("Backlinks collection operators", () => { const anyResult = realm.objects(Item).filtered( // :snippet-start: backlinks-collection-operators - // Find items where no project that references the item - // has a quota greater than 10. + // Find items where no project that references the item has a quota greater than 10. "NONE @links.Project.items.quota > 10" + // :remove-start: ); expect(anyResult.length).toBe(5); const allResult = realm.objects(Item).filtered( // :remove-end: - - // Find items where all projects that reference the item - // have a quota less than 5. + // Find items where all projects that reference the item have a quota less than 5. "ALL @links.Project.items.quota < 5" - // :remove-start: + // :remove-start: ); expect(allResult.length).toBe(5); }); @@ -714,9 +689,9 @@ describe("Realm Query Language Reference", () => { test("Backlinks aggregate operators", () => { const shallowResultLinkingObjects = realm.objects(Item).filtered( // :remove-end: - // Find items that are referenced by multiple projects. "projects.@count > 1" + // :remove-start: ); expect(shallowResultLinkingObjects.length).toBe(1); @@ -724,9 +699,9 @@ describe("Realm Query Language Reference", () => { const shallowResultAtLinks = realm.objects(Item).filtered( // :remove-end: - // Find items that are not referenced by any project. "@links.Project.items.@count == 0" + // :remove-start: ); expect(shallowResultAtLinks.length).toBe(1); @@ -734,10 +709,9 @@ describe("Realm Query Language Reference", () => { const deepResultAtLinks = realm.objects(Item).filtered( // :remove-end: - - // Find items that belong to a project where the average item has - // been worked on for at least 10 minutes + // Find items that belong to a project where the average item has been worked on for at least 10 minutes "@links.Project.items.items.@avg.progressMinutes > 10" + // :remove-start: ); expect(deepResultAtLinks.length).toBe(2); @@ -747,9 +721,7 @@ describe("Realm Query Language Reference", () => { test("Count all backlinks (@links.@count)", () => { const result = realm.objects(Item).filtered( // :remove-end: - - // Find items that are not referenced by another - // object of any type (backlink count is 0). + // Find items that are not referenced by another object of any type (backlink count is 0). "@links.@count == 0" // :snippet-end: ); @@ -763,24 +735,22 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects(Project); const mixedString = projects.filtered( // :snippet-start: type-operator - // Find projects with an `additionalInfo` property of - // string type. + // Find projects with an `additionalInfo` property of string type. "additionalInfo.@type == 'string'" + // :remove-start: ); const mixedCollection = projects.filtered( // :remove-end: - // Find projects with an `additionalInfo` property of // `collection` type, which matches list or dictionary types. "additionalInfo.@type == 'collection'" + // :remove-start: ); const mixedBool = projects.filtered( // :remove-end: - - // Find projects with an `additionalInfo` property of - // list type, where any list element is of type 'bool'. + // Find projects with an `additionalInfo` property of list type, where any list element is of type 'bool'. "additionalInfo[*].@type == 'bool'" // :snippet-end: ); @@ -799,12 +769,9 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const res2 = realm.objects(Item).filtered( // :remove-end: - - // 'null' maps to the SDK language's null pointer - "assignee == $0", null + "assignee == $0", null // 'null' maps to the SDK language's null pointer // :snippet-end: ); - expect(res.length).toBe(1); expect(res2.length).toBe(1); }); @@ -851,18 +818,17 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const oidStringLiteral = oidUuids.filtered( // :snippet-start: oid - // Find an item whose `_id` matches the ObjectID - // value passed to 'oid()'. + // Find an item whose `_id` matches the ObjectID value passed to 'oid()'. "_id == oid(6001c033600510df3bbfd864)" + // :remove-start: ); const oidInterpolation = oidUuids.filtered( // :remove-end: - - // Find an item whose `_id` matches the ObjectID - // passed as a parameterized query argument. + // Find an item whose `_id` matches the ObjectID passed as a parameterized query argument. "_id == $0", oidValue + // :remove-start: ); @@ -873,9 +839,7 @@ describe("Realm Query Language Reference", () => { const oidUuids = realm.objects("OidUuid"); const uuid = oidUuids.filtered( // :remove-end: - - // Find an item whose `id` matches the UUID value - // passed to 'uuid()'. + // Find an item whose `id` matches the UUID value passed to 'uuid()'. "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" // :remove-start: @@ -883,9 +847,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const test = oidUuids.filtered( // :remove-end: - - // Find an item whose `_id` matches the UUID - // passed as a parameterized query argument. + // Find an item whose `_id` matches the UUID passed as a parameterized query argument. "id == $0", uuidValue // :snippet-end: ); @@ -943,14 +905,13 @@ describe("Realm Query Language Reference", () => { // :snippet-start: date-parameterized-query // Find to-do items completed before today's date. "dateCompleted < $0", today + // :remove-start: ); const dateAlt1 = dates.filtered( // :remove-end: - - // Find to-do items completed between the start of the year - // until today. + // Find to-do items completed between the start of the year until today. "dateCompleted > $0 AND dateCompleted < $1", thisYear, today // :snippet-end: ); @@ -988,7 +949,6 @@ describe("Realm Query Language Reference", () => { "name TEXT $0", "wri*" // :snippet-end: ); - expect(itemsWithWrite.length).toBe(2); expect(itemsWithWriteNotTest.length).toBe(0); expect(itemsStartingWithWri.length).toBe(2); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst index ba78aca6c3..711195cbdf 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst @@ -11,6 +11,7 @@ // Find projects where minimum `priority` of all items is 5. "items.@min.priority > $0", priorityNum + // Find projects with more than 5 items. "items.@count > $0", 5 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst index fa70358f91..e56bd53246 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst @@ -1,11 +1,9 @@ .. code-block:: typescript - // Find items where no project that references the item - // has a quota greater than 10. + // Find items where no project that references the item has a quota greater than 10. "NONE @links.Project.items.quota > 10" - // Find items where all projects that reference the item - // have a quota less than 5. + // Find items where all projects that reference the item have a quota less than 5. "ALL @links.Project.items.quota < 5" // Find items that are referenced by multiple projects. @@ -14,10 +12,8 @@ // Find items that are not referenced by any project. "@links.Project.items.@count == 0" - // Find items that belong to a project where the average item has - // been worked on for at least 10 minutes + // Find items that belong to a project where the average item has been worked on for at least 10 minutes "@links.Project.items.items.@avg.progressMinutes > 10" - // Find items that are not referenced by another - // object of any type (backlink count is 0). + // Find items that are not referenced by another object of any type (backlink count is 0). "@links.@count == 0" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst index e1a9e51086..8373b6c723 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst @@ -1,6 +1,5 @@ .. code-block:: typescript - // Find items that belong to a project with a quota greater than 10 - // through the Item object's `projects` property + // Find items that belong to a project with a quota greater than 10 through the Item object's `projects` property // (using 'LinkingObjects'). "projects.quota > 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst index f58f72e118..8676d1768b 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst @@ -2,6 +2,7 @@ // Evaluate against an item's `priority` property value: "2 * priority > 6" // resolves to `priority > 3` + "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` // Evaluate against multiple object property values: diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst index f83e455b95..84700fcada 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst @@ -3,6 +3,5 @@ // Find to-do items completed before today's date. "dateCompleted < $0", today - // Find to-do items completed between the start of the year - // until today. + // Find to-do items completed between the start of the year until today. "dateCompleted > $0 AND dateCompleted < $1", thisYear, today diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst index 6e20a8cfe1..8ff782049e 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst @@ -1,5 +1,4 @@ .. code-block:: typescript - // Find projects whose `projectLocation` property contains - // an embedded Address object with a specific zip code. + // Find projects whose `projectLocation` property contains an embedded Address object with a specific zip code. "projectLocation.address.zipcode == 10019" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst index 8b2bed7db4..239ef65d49 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst @@ -1,21 +1,16 @@ .. code-block:: typescript - // Find projects whose `comments` dictionary property - // have a key of 'status'. + // Find projects whose `comments` dictionary property have a key of 'status'. "comments.@keys == $0", "status" - // Find projects whose `comments` dictionary property - // have a 'status' key with a value that ends in 'track'. + // Find projects whose `comments` dictionary property have a 'status' key with a value that ends in 'track'. "comments['status'] LIKE $0", "*track" - // Find projects whose `comments` dictionary property - // have more than one key-value pair. + // Find projects whose `comments` dictionary property have more than one key-value pair. "comments.@count > $0", 1 - // Find projects whose `comments` dictionary property - // contains only values of type 'string'. + // Find projects whose `comments` dictionary property contains only values of type 'string'. "ALL comments.@type == 'string'" - // Find projects whose `comments` dictionary property - // contains no values of type 'int'. + // Find projects whose `comments` dictionary property contains no values of type 'int'. "NONE comments.@type == 'int'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst index 011a3715b4..569a31cb43 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst @@ -1,5 +1,4 @@ .. code-block:: typescript - // Find projects whose `items` list property contains - // an Item object with a specific name. + // Find projects whose `items` list property contains an item with a specific name. "items[0].name == 'Approve project plan'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst index f35fae515e..6eb90698e5 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst @@ -3,5 +3,3 @@ "assignee == ANY { $0, $1 }", "Alex", "Ali" "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) - - "assignee NONE { 'Alex', 'Ali' }" // Equivalent to != ANY. diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst index ab5fef1b83..1a30b8df8d 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst @@ -1,5 +1,4 @@ .. code-block:: typescript - // Find an item with the specified ObjectId value - // in the `items` collection. + // Find an item with the specified ObjectId value in the `items` collection. "oid(631a072f75120729dc9223d9) IN items._id" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst index 5a3fc8f1d4..f51335bf6e 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst @@ -5,6 +5,5 @@ new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; - // Find items with an ObjectId value matching any value in the - // parameterized list. + // Find items with an ObjectId value matching any value in the parameterized list. const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst index df932d00da..94f7565ae0 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst @@ -1,5 +1,4 @@ .. code-block:: typescript - // Find items with a priority value matching - // any value in the static list. + // Find items with a priority value matching any value in the static list. "priority IN {0, 1, 2}" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst index 91769b4891..6b39c15029 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst @@ -1,6 +1,4 @@ .. code-block:: typescript "assignee == nil" - - // 'null' maps to the SDK language's null pointer - "assignee == $0", null + "assignee == $0", null // 'null' maps to the SDK language's null pointer diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst index cb00dbe046..e7cc775293 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst @@ -1,18 +1,13 @@ .. code-block:: typescript - // Find an item whose `_id` matches the ObjectID - // value passed to 'oid()'. + // Find an item whose `_id` matches the ObjectID value passed to 'oid()'. "_id == oid(6001c033600510df3bbfd864)" - // Find an item whose `_id` matches the ObjectID - // passed as a parameterized query argument. + // Find an item whose `_id` matches the ObjectID passed as a parameterized query argument. "_id == $0", oidValue - // Find an item whose `id` matches the UUID value - // passed to 'uuid()'. + // Find an item whose `id` matches the UUID value passed to 'uuid()'. "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" - - // Find an item whose `_id` matches the UUID - // passed as a parameterized query argument. + // Find an item whose `_id` matches the UUID passed as a parameterized query argument. "id == $0", uuidValue diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst index e1d7564bc5..c37c93351e 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst @@ -3,6 +3,5 @@ // Include one parameter with `$0`. "progressMinutes > 1 AND assignee == $0", "Ali" - // Include multiple parameters using ascending integers, - // starting at`$0`. + // Include multiple parameters using ascending integers, starting at`$0`. "progressMinutes > $0 AND assignee == $1", 1, "Alex" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst index 3b9ac369fa..2f83d4846f 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst @@ -1,3 +1,6 @@ .. code-block:: typescript const expression = "priority == 1"; + // Property Name: priority + // Operator: == + // Value: 1 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst index 92c1c2d89a..84cac7abce 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst @@ -9,10 +9,8 @@ // Find projects that only contain completed items. "ALL items.isComplete == $0", true - // Find projects with at least one item assigned to - // either Alex or Ali. + // Find projects with at least one item assigned to either Alex or Ali. "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" - // Find projects with no items assigned to either - // Alex or Ali. + // Find projects with no items assigned to either Alex or Ali. "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst index 200a1408d7..298188b200 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst @@ -2,8 +2,7 @@ // 1. Sorts by highest priority. // 2. Returns the first item. - // 3. Remove duplicate names (N/A because a single - // item is always considered distinct). + // 3. Remove duplicate names (N/A because a single item is always considered distinct). "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" // 1. Removes any duplicates by name. diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst index b4580eadc9..3268f78dec 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst @@ -1,12 +1,12 @@ .. code-block:: typescript - // Find incomplete items, sort by `priority` - // in descending order, then sort equal `priority` - // values by `progressMinutes` in ascending order. + // Find incomplete items, sort by `priority` in descending order, then + // sort equal `priority` values by `progressMinutes` in ascending order. "isComplete == false SORT(priority DESC, progressMinutes ASC)" - // Find high priority items, then remove from the results - // any items with duplicate `name` AND `assignee` values. + // Find high priority items, then remove from the results any items + // with duplicate values for both `name` AND `assignee` properties. "priority >= 5 DISTINCT(name, assignee)" + // Find in-progress items, then return the first 10 results. "progressMinutes > 0 && isComplete != true LIMIT(10)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst index e1254e7ed6..7fd3874072 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst @@ -1,17 +1,13 @@ .. code-block:: typescript - // Find projects whose name starts with 'E' or 'e' - // (case-insensitive). + // Find projects whose name starts with 'E' or 'e' (case-insensitive). "name BEGINSWITH[c] $0", "E" - // Find projects whose name contains 'ie' - // (case-sensitive). + // Find projects whose name contains 'ie' (case-sensitive). "name CONTAINS $0", "ie" - // Find items where the assignee name is lexicographically - // between 'Ali' and 'Chris' (case-sensitive). + // Find items where the assignee name is lexicographically between 'Ali' and 'Chris' (case-sensitive). "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" - - // Find projects where the street address is lexicographically - // greater than '123 Main St' (case-sensitive). + + // Find projects where the street address is lexicographically greater than '123 Main St' (case-sensitive). "projectLocation.address.street > $0", "123 Main St" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst index 126129f7e2..8b4e249ed2 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst @@ -3,6 +3,5 @@ // Find projects with incomplete items with 'Demo' in the name. "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" - // Find projects where the number of completed items - // is greater than or equal to the project's `quota` property. + // Find projects where the number of completed items is greater than or equal to the project's `quota` property. "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst index fc9ad3f4df..c59fce1484 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst @@ -1,13 +1,11 @@ .. code-block:: typescript - // Find projects with an `additionalInfo` property of - // string type. + // Find projects with an `additionalInfo` property of string type. "additionalInfo.@type == 'string'" // Find projects with an `additionalInfo` property of // `collection` type, which matches list or dictionary types. "additionalInfo.@type == 'collection'" - // Find projects with an `additionalInfo` property of - // list type, where any list element is of type 'bool'. + // Find projects with an `additionalInfo` property of list type, where any list element is of type 'bool'. "additionalInfo[*].@type == 'bool'" diff --git a/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst b/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst new file mode 100644 index 0000000000..af738f729f --- /dev/null +++ b/source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst @@ -0,0 +1,33 @@ +.. code-block:: javascript + + const Item = { + name: "Item", + properties: { + _id: "objectId", + name: { type: "string", indexed: "full-text" }, + isComplete: { type: "bool", default: false }, + assignee: "string?", + priority: { type: "int", default: 0 }, + progressMinutes: { type: "int", default: 0 }, + projects: { + type: "linkingObjects", + objectType: "Project", + property: "items", + }, + }, + primaryKey: "_id", + }; + + const Project = { + name: "Project", + properties: { + _id: "objectId", + name: "string", + items: "Item[]", + quota: "int?", + comments: "string?{}", + projectLocation: "Office?", + additionalInfo: "mixed", + }, + primaryKey: "_id", + }; diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index c5d461c791..7d0602c802 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -53,18 +53,85 @@ Examples on This Page --------------------- Most of the examples on this page use a simple data set for a to-do list app -that include the following database objects: -The two Realm object types are ``Project`` and ``Item``. +that include the following database object types: - ``Item``: Each item object has a name, assignee's name, and completed flag. - There is also an arbitrary number for priority (higher is more important) - and a count of minutes spent working on it. -- A ``Project`` has zero or more ``Items`` and an optional quota + There is also an arbitrary number for priority (where higher is more + important) and a count of minutes spent working on it. +- ``Project``: Each project object has zero or more ``Items`` and an optional quota for minimum number of to-do items expected to be completed. -See the schema for these two classes, ``Project`` and ``Item``, below: +.. tabs-drivers:: + + tabs: + - id: cpp + content: | + + .. literalinclude:: /examples/generated/cpp/asymmetric-sync.snippet.create-asymmetric-object.cpp + :language: cpp + + - id: csharp + content: | + + .. literalinclude:: /examples/generated/dotnet/RqlSchemaExamples.snippet.rql-schema-examples.cs + :language: csharp + + - id: dart + content: | + + .. literalinclude:: /examples/generated/flutter/task_project_models_test.snippet.task-project-models.dart + :language: dart + + - id: java + content: | + + .. code-block:: java + + public class Item extends RealmObject { + ObjectId id = new ObjectId(); + String name; + Boolean isComplete = false; + String assignee; + Integer priority = 0; + Integer progressMinutes = 0; + @LinkingObjects("items") + final RealmResults projects = null; + } + public class Project extends RealmObject { + ObjectId id = new ObjectId(); + String name; + RealmList items; + Integer quota = null; + } + + - id: javascript + content: | + + source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst + + - id: kotlin + content: | + + .. literalinclude:: /examples/generated/kotlin/RQLTest.snippet.rql-schema-example.kt + :language: kotlin + + - id: objectivec + content: | + + .. literalinclude:: /examples/MissingExamplePlaceholders/missing.m + :language: objectivec + + - id: swift + content: | + + .. literalinclude:: /examples/MissingAPIPlaceholders/missing.swift + :language: swift + + - id: typescript + content: | + + .. include:: source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst -.. includes:: source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst Query Syntax ------------ @@ -75,18 +142,26 @@ Realm Query Language syntax is based on `NSPredicate Queries evaluate a predicate for every object in the collection being queried. If the predicate resolves to ``true``, the results collection includes the object. -Realm Query Language uses expressions and predicates to evaluate queries. +Realm Query Language uses expressions and predicates to filter objects. Filters +consist of expressions within a predicate that evaluate to ``true`` or +``false``. + +Each expression contains the following elements: -- **Expressions** are the building blocks of queries. They can be simple or complex. - For example, ``name == 'Ali'`` is a simple expression, while - ``name == 'Ali' AND priority > 5`` is a complex expression. -- **Predicates** are expressions that evaluate to ``true`` or ``false``. - For example, ``name == 'Ali'`` is a predicate that evaluates to ``true`` - if the name property is 'Ali'. - Realm Query Language also supports the following predicates: +- The name of the object property to evaluate. +- An operator and *up to two* argument expressions. For example, in the + expression ``A + B``, the entirety of ``A + B`` is an expression, but ``A`` + and ``B`` are also argument expressions to the operator ``+``. +- A value, such as a string (``'hello'``) or a number (``5``). - - ``TRUEPREDICATE`` - Matches all objects. This is the default predicate. - - ``FALSEPREDICATE`` - Matches no objects. +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst + +Expressions can be combined with :ref:`logical operators ` to create compound predicates. + +Realm Query Language also supports the following special predicates: + +- ``TRUEPREDICATE`` - Always evaluates to ``true`` (returns all objects). +- ``FALSEPREDICATE`` - Always evaluates to ``false`` (returns no objects). .. _rql-parameterized-queries: @@ -94,19 +169,18 @@ Realm Query Language uses expressions and predicates to evaluate queries. Parameterized vs. Serialized Queries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can format queries in the following two ways: +You can format queries in serialized or parameterized format. Unless otherwise +noted, both formats are supported for a given query type. -- **Serialized queries** pass values directly in the expression. +- Serialized queries pass values directly in the expression. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.serialized-query.ts.rst -- **Parameterized queries** pass interpolated variables as additional +- Parameterized queries pass interpolated variables as additional arguments. The syntax for interpolated variables is ``$``, starting at ``0`` and incrementing for each additional variable. - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst - -Unless otherwise noted, both formats are supported. + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst Dot Notation ~~~~~~~~~~~~ @@ -141,8 +215,8 @@ to ``nil``. .. _rql-operators: -Operators ---------- +General Operators +----------------- .. _rql-comparison-operators: @@ -150,7 +224,8 @@ Operators Comparison Operators ~~~~~~~~~~~~~~~~~~~~ -Use comparison operators to compare values of matching data types. +Use comparison operators to compare values of matching data types. String values +are compared :wikipedia:`lexicographically `. .. list-table:: :header-rows: 1 @@ -163,54 +238,27 @@ Use comparison operators to compare values of matching data types. - Evaluates to ``true`` if the left-hand expression (``X``) is between or equal to the right-hand expression (``Y``) range. - - For dates, this evaluates to ``true`` if the left-hand date is within the right-hand date range. - - For strings, this evaluates to ``true`` if the left-hand string is - lexicographically within the right-hand range. - * - | ``==``, ``=`` - - Evaluates to ``true`` if the left-hand expression is equal - to the right-hand expression. - - - For strings, this evaluates to ``true`` if the left-hand string is - lexicographically equal to the right-hand string. + - Evaluates to ``true`` if the left-hand expression is equal to the right-hand expression. * - | ``>`` - - Evaluates to ``true`` if the left-hand numerical or date expression - is greater than the right-hand numerical or date expression. - - - For dates, this evaluates to ``true`` if the left-hand date is later - than the right-hand date. - - For strings, this evaluates to ``true`` if the left-hand string is - lexicographically greater than the right-hand string. + - Evaluates to ``true`` if the left-hand expression is greater than the right-hand expression. For dates, this evaluates to ``true`` if the left-hand date is later than the right-hand date. * - | ``>=`` - - Evaluates to ``true`` if the left-hand expression - is greater than or equal to the right-hand expression. - - - For dates, this evaluates to ``true`` if the left-hand date is later than - or the same as the right-hand date. - - For strings, this evaluates to ``true`` if the left-hand string is lexicographically greater than or equal to the right-hand string. + - Evaluates to ``true`` if the left-hand expression is greater than or equal to the right-hand expression. For dates, this evaluates to ``true`` if the left-hand date is later than or the same as the right-hand date. * - | ``IN`` - Evaluates to ``true`` if the left-hand expression is in the right-hand list. This is equivalent to and used as a shorthand - for ``== ANY``. + for ``== ANY`` :ref:`collection operator `. * - | ``<`` - Evaluates to ``true`` if the left-hand numerical or date expression - is less than the right-hand numerical or date expression. - - - For dates, this evaluates to ``true`` if the left-hand date is earlier - than the right-hand date. - - For strings, this evaluates to ``true`` if the left-hand string is lexicographically less than the right-hand string. + is less than the right-hand numerical or date expression. For dates, this evaluates to ``true`` if the left-hand date is earlier than the right-hand date. * - | ``<=`` - Evaluates to ``true`` if the left-hand numeric expression is less than - or equal to the right-hand numeric expression. - - - For dates, this evaluates to ``true`` if the left-hand date is earlier - than or the same as the right-hand date. - - For strings, this evaluates to ``true`` if the left-hand string is lexicographically less than or equal to the right-hand string. + or equal to the right-hand numeric expression. For dates, this evaluates to ``true`` if the left-hand date is earlier than or the same as the right-hand date. * - | ``!=``, ``<>`` - Evaluates to ``true`` if the left-hand expression is not equal @@ -251,13 +299,13 @@ Use logical operators to create compound predicates. * - Operator - Description - * - | ``AND`` | ``&&`` + * - | ``AND`` | ``&&`` - Evaluates to ``true`` if both left-hand and right-hand expressions are ``true``. - * - | ``NOT`` | ``!`` + * - | ``NOT`` | ``!`` - Negates the result of the given expression. - * - | ``OR`` | ``||`` + * - | ``OR`` | ``||`` - Evaluates to ``true`` if either expression returns ``true``. The following example uses logical operators to combine multiple predicates: @@ -312,8 +360,7 @@ Use aggregate operators to traverse a collection and reduce it to a single value * - | ``@avg`` - Evaluates to the average value of a given numerical property across - a collection. If any values are ``null``, they are not counted - in the result. + a collection. ``null`` values are ignored. * - | ``@count`` - Evaluates to the number of objects in the given collection. @@ -327,50 +374,14 @@ Use aggregate operators to traverse a collection and reduce it to a single value across a collection. ``null`` values are ignored. * - | ``@sum`` - - Evaluates to the sum of a given numerical property across a collection, - excluding ``null`` values. + - Evaluates to the sum of a given numerical property across a collection. + ``null`` values are ignored. The following example uses aggregate operators to find projects whose ``items`` collection property meets certain criteria: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst - -.. _rql-collection-operators: - -Collection Operators -~~~~~~~~~~~~~~~~~~~~ - -A **collection operator** lets you query list properties within a collection of objects. -Collection operators filter a collection by applying a predicate -to every element of a given list property of the object. -If the predicate returns true, the object is included in the output collection. - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Operator - - Description - - * - ``ALL`` - - Returns objects where the predicate evaluates to ``true`` for all objects - in the collection. - - * - ``ANY``, ``SOME`` - - Returns objects where the predicate evaluates to ``true`` for any objects - in the collection. - - * - ``NONE`` - - Returns objects where the predicate evaluates to false for all objects - in the collection. - -The following example uses collection operators to find projects whose ``items`` -collection property meets certain criteria - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst - - .. _rql-sort-distinct-limit: Sort, Distinct, and Limit Operators @@ -401,8 +412,7 @@ are applied in the order they appear in the query. * - ``LIMIT`` - Limit the results collection to the specified number. -The following example finds all incomplete items, then -shapes the returned results using sort, distinct, and limit operators: +The following example finds all incomplete items, then shapes the returned results: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst @@ -419,6 +429,40 @@ shapes the returned results using sort, distinct, and limit operators: Type-Specific Operators ----------------------- +.. _rql-collection-operators: + +Collection Operators +~~~~~~~~~~~~~~~~~~~~ + +A collection operator lets you query list properties within a collection of objects. +Collection operators filter a collection by applying a predicate +to every element of a given list property of the object. +If the predicate returns true, the object is included in the output collection. + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Operator + - Description + + * - ``ALL`` + - Returns objects where the predicate evaluates to ``true`` for all objects + in the collection. + + * - ``ANY``, ``SOME`` + - Returns objects where the predicate evaluates to ``true`` for any objects + in the collection. ``ANY`` is the default operator for list comparisons. + + * - ``NONE`` + - Returns objects where the predicate evaluates to false for all objects + in the collection. + +The following example uses collection operators to find projects whose ``items`` +collection property meets certain criteria + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst + .. _rql-type-operator: @@ -427,22 +471,17 @@ Type Operator Check the data type of a mixed type or dictionary property using the ``@type`` operator. Evaluate the property against a string representation of the -data type name using string comparison operators. - -For information on how each SDK language's data types map to database-specific data types, refer to :ref:`sdks-data-types`. - -You can currently only use the type operator with mixed types and -dictionaries. +data type name using string comparison operators. For information on how each SDK language's data types map to database-specific data types, refer to :ref:`sdks-data-types`. .. list-table:: :header-rows: 1 - :widths: 40 60 + :widths: 20 80 * - Operator - Description * - ``@type`` - - Check if type of a property is the specified data type represented as a string. + - Check if type of a mixed type or dictionary property is the specified data type represented as a string. Use ``==`` and ``!=`` to compare equality. The following example uses the ``@type`` operator to find projects @@ -451,6 +490,10 @@ criteria: .. include:: examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst +.. note:: Only Supported for Mixed Data Types and Dictionaries + + You can currently only use the ``@type`` operator with mixed data types and + dictionary properties. .. _rql-dictionary-operators: @@ -499,7 +542,7 @@ to filter objects based on string values. SDKs evaluate string values .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator or Modifier - Description @@ -555,9 +598,7 @@ List Comparisons Use :ref:`comparison operators ` and :ref:`collection operators ` to filter based -on lists of data. - -You can compare any type of valid list, including: +on lists of data. You can compare any type of valid list, including: - Collections of objects, which let you filter against other data in the database. @@ -636,8 +677,8 @@ lists and comparison operators: .. _rql-objectid-uuid-operators: -ObjectId and UUID Comparisons -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ObjectId and UUID Queries +~~~~~~~~~~~~~~~~~~~~~~~~~ Use :ref:`comparison operators ` to compare :manual:`BSON ObjectIds ` and :manual:`UUIDs ` for equality. These data types are @@ -648,7 +689,7 @@ arguments or to the ``oid()`` or ``uuid()`` predicate functions, respectively. .. list-table:: :header-rows: 1 - :widths: 40 60 + :widths: 30 70 * - Operator - Description @@ -665,8 +706,8 @@ The following examples use equality comparison operators to find items based on .. _rql-date-operators: -Date Comparisons -~~~~~~~~~~~~~~~~ +Date Queries +~~~~~~~~~~~~ Use :ref:`comparison operators ` to query date types. @@ -702,7 +743,7 @@ corresponding backlink. .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator - Description @@ -744,7 +785,7 @@ search (FTS) annotation. For information on enabling FTS on a property, refer to .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator - Description @@ -783,11 +824,11 @@ Geospatial Queries ~~~~~~~~~~~~~~~~~~ Use the ``geoWithin`` operator to query geospatial data. For more information on -defining and working with geospatial data, refer to :ref:`sdks-define-geospatial-object`. +defining geospatial data, refer to :ref:`sdks-define-geospatial-object`. .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator - Description @@ -801,6 +842,17 @@ defining and working with geospatial data, refer to :ref:`sdks-define-geospatial - ``GeoBox`` - ``GeoPolygon`` +A geospatial query consists of: + +- An object with a property containing the embedded geospatial data. +- A defined geospatial shape to set the boundary for the query: + - ``GeoCircle`` + - ``GeoBox`` + - ``GeoPolygon`` + +The query evaluates ``true`` if the coordinates of the embedded property are +within the boundaries of the geospatial shape. + The following example compares the coordinates of the embedded ``location`` property against the boundaries of the ``GeoCircle`` shape named @@ -808,9 +860,9 @@ shape named .. include:: /examples/generated/node/v12/geospatial.test.snippet.rql-geospatial.ts.rst -.. important:: Geospatial Data Does Not Support Parameterized Queries +.. important:: Geospatial Queries Do Not Support Parameterized Queries - You cannot use parameterized queries with geospatial data. + You cannot use :ref:`parameterized queries ` with geospatial data. .. _rql-subqueries: @@ -827,7 +879,7 @@ Subqueries use the following syntax: .. list-table:: :header-rows: 1 - :widths: 40 60 + :widths: 20 80 * - Operator - Description @@ -836,7 +888,8 @@ Subqueries use the following syntax: - Returns list objects for the specified collection where the predicate evaluates to ``true``. Contains the following parameters: - - ``collection``: The name of the list property to iterate through. + - ``collection``: The name of the list property to iterate through. This + must be a list of objects, not a list of primitive types. - ``variableName``: A variable name of the element to use in the subquery, prefixed with ``$``. - ``predicate``: The subquery predicate. Use the variable specified by ``variableName`` to refer to the currently-iterated element. @@ -855,8 +908,6 @@ The following example uses subquery filters to find projects based on the The ``@count`` aggregate operator returns the number of objects in the subquery results collection. You can compare the count with the number ``0`` to return all matching objects. - - .. _flexible-sync-rql-limitations: Flexible Sync RQL Limitations From e4f9c8f4bad1453cf260a3835d8db5764782f0d7 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Fri, 31 May 2024 10:39:35 -0400 Subject: [PATCH 09/12] Fix autobuilder errors --- ...spatial.test.snippet.rql-geospatial.js.rst | 3 + .../query/rql-example-data-model.rst | 55 ++- .../query-engines/realm-query-language.txt | 314 ++++++++++-------- 3 files changed, 201 insertions(+), 171 deletions(-) create mode 100644 source/examples/generated/node/v12/formatted/geospatial.test.snippet.rql-geospatial.js.rst diff --git a/source/examples/generated/node/v12/formatted/geospatial.test.snippet.rql-geospatial.js.rst b/source/examples/generated/node/v12/formatted/geospatial.test.snippet.rql-geospatial.js.rst new file mode 100644 index 0000000000..ac21e33fe0 --- /dev/null +++ b/source/examples/generated/node/v12/formatted/geospatial.test.snippet.rql-geospatial.js.rst @@ -0,0 +1,3 @@ +.. code-block:: javascript + + "location geoWithin $0", smallCircle diff --git a/source/includes/sdk-examples/query/rql-example-data-model.rst b/source/includes/sdk-examples/query/rql-example-data-model.rst index 7f866902ab..f7e9d65642 100644 --- a/source/includes/sdk-examples/query/rql-example-data-model.rst +++ b/source/includes/sdk-examples/query/rql-example-data-model.rst @@ -4,7 +4,7 @@ - id: cpp content: | - .. literalinclude:: /examples/generated/cpp/asymmetric-sync.snippet.create-asymmetric-object.cpp + .. literalinclude:: /examples/generated/cpp/filter-data.snippet.models.cpp :language: cpp - id: csharp @@ -22,30 +22,29 @@ - id: java content: | - .. code-block:: java - - public class Item extends RealmObject { - ObjectId id = new ObjectId(); - String name; - Boolean isComplete = false; - String assignee; - Integer priority = 0; - Integer progressMinutes = 0; - @LinkingObjects("items") - final RealmResults projects = null; - } - public class Project extends RealmObject { - ObjectId id = new ObjectId(); - String name; - RealmList items; - Integer quota = null; - } + .. code-block:: java + + public class Item extends RealmObject { + ObjectId id = new ObjectId(); + String name; + Boolean isComplete = false; + String assignee; + Integer priority = 0; + Integer progressMinutes = 0; + @LinkingObjects("items") + final RealmResults projects = null; + } + public class Project extends RealmObject { + ObjectId id = new ObjectId(); + String name; + RealmList items; + Integer quota = null; + } - id: javascript content: | - .. literalinclude:: /examples/generated/node/rql-data-models.snippet.rql-data-models.js - :language: javascript + .. include:: /examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst - id: kotlin content: | @@ -53,19 +52,7 @@ .. literalinclude:: /examples/generated/kotlin/RQLTest.snippet.rql-schema-example.kt :language: kotlin - - id: objectivec - content: | - - .. literalinclude:: /examples/MissingPlaceholders/api.m - :language: objectivec - - - id: swift - content: | - - .. literalinclude:: /examples/MissingPlaceholders/api.swift - :language: swift - - id: typescript content: | - .. include:: /examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst + .. include:: /examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index 7d0602c802..33725bf92f 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -6,8 +6,8 @@ Realm Query Language (RQL) ========================== .. meta:: - :description: Use Realm Query Language (RQL) to retrieve objects from the database. - :keywords: Realm, Flutter SDK, Kotlin SDK, Java SDK, Node.js SDK, code example + :description: Use Realm Query Language (RQL) with Atlas Device SDK methods to retrieve objects from the database. + :keywords: Realm, C++ SDK, Flutter SDK, Kotlin SDK, .NET SDK, Java SDK, Node.js SDK, code example .. facet:: :name: genre @@ -35,8 +35,9 @@ to the Realm database query engine, which retrieves matching database objects. The Swift SDK does *not* support querying with Realm Query Language. Instead, it uses NSPredicate to query a database. For more information, refer to :ref:`Type-Safe and NSPredicate Queries (Swift SDK) `. -With the exception of the Swift SDK, you can use Realm Query Language with your preferred SDK's filter -or query methods. For more information, refer to :ref:`sdks-crud-read`. +With the exception of the Swift SDK, you can use Realm Query Language with your +preferred SDK's filter or query methods. For more information, refer to +:ref:`sdks-crud-read`. The following SDKs also support language-specific idiomatic APIs for querying databases: @@ -61,76 +62,7 @@ that include the following database object types: - ``Project``: Each project object has zero or more ``Items`` and an optional quota for minimum number of to-do items expected to be completed. -.. tabs-drivers:: - - tabs: - - id: cpp - content: | - - .. literalinclude:: /examples/generated/cpp/asymmetric-sync.snippet.create-asymmetric-object.cpp - :language: cpp - - - id: csharp - content: | - - .. literalinclude:: /examples/generated/dotnet/RqlSchemaExamples.snippet.rql-schema-examples.cs - :language: csharp - - - id: dart - content: | - - .. literalinclude:: /examples/generated/flutter/task_project_models_test.snippet.task-project-models.dart - :language: dart - - - id: java - content: | - - .. code-block:: java - - public class Item extends RealmObject { - ObjectId id = new ObjectId(); - String name; - Boolean isComplete = false; - String assignee; - Integer priority = 0; - Integer progressMinutes = 0; - @LinkingObjects("items") - final RealmResults projects = null; - } - public class Project extends RealmObject { - ObjectId id = new ObjectId(); - String name; - RealmList items; - Integer quota = null; - } - - - id: javascript - content: | - - source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.js.rst - - - id: kotlin - content: | - - .. literalinclude:: /examples/generated/kotlin/RQLTest.snippet.rql-schema-example.kt - :language: kotlin - - - id: objectivec - content: | - - .. literalinclude:: /examples/MissingExamplePlaceholders/missing.m - :language: objectivec - - - id: swift - content: | - - .. literalinclude:: /examples/MissingAPIPlaceholders/missing.swift - :language: swift - - - id: typescript - content: | - - .. include:: source/examples/generated/node/v12/formatted/rql-data-models.snippet.rql-data-models.ts.rst +.. include:: /includes/sdk-examples/query/rql-example-data-model.rst Query Syntax @@ -156,7 +88,8 @@ Each expression contains the following elements: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst -Expressions can be combined with :ref:`logical operators ` to create compound predicates. +Expressions can be combined with :ref:`logical operators ` +to create compound predicates. Realm Query Language also supports the following special predicates: @@ -169,8 +102,7 @@ Realm Query Language also supports the following special predicates: Parameterized vs. Serialized Queries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can format queries in serialized or parameterized format. Unless otherwise -noted, both formats are supported for a given query type. +You can format queries in serialized or parameterized format. - Serialized queries pass values directly in the expression. @@ -182,12 +114,84 @@ noted, both formats are supported for a given query type. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst +The following table shows how a query should be formatted when serialized and +parameterized for the specific data types: + +.. list-table:: + :header-rows: 1 + :widths: 15 25 25 35 + + * - Type + - Parameterized Example + - Serialized Example + - Note + + * - :ref:`Nil ` + - "assignee == $0", null + - "assignee == nil" + - For parameterized queries, ``nill`` maps to each SDK's respective null pointer. + + * - Boolean + - "setting == $0", false + - "setting == false" + - ``true`` or ``false`` values. + + * - :ref:`String ` + - "name == $0", "George" + - "name == 'George'" + - Applies to ``string`` and ``char`` data type. + + * - :ref:`Number ` + - "age > $0", 5.50 + - "age > 5.50" + - Applies to ``int``, ``short``, ``long``, ``double``, ``Decimal128``, and ``float`` data types. + + * - :ref:`Date ` + - "date < $0", dateObject + - "date < 2021-02-20\@17:30:15:0" + - For parameterized queries, you must pass in a date object. + For serialized queries, the representation can be a + :ref:`supported Date format ` or a parameterized ``Date`` object. + + * - :ref:`ObjectID ` + - "_id == $0", oidValue + - "_id == oid(507f1f77bcf86cd799439011)" + - For parameterized queries, you must pass in an ObjectId. + For serialized queries, the string representation is ``oid()``. + + * - :ref:`UUID ` + - "id == $0", uuidValue + - "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" + - For parameterized queries, you must pass in a UUID. + For serialized queries, the string representation is ``uuid()``. + + * - Binary + - "value == $0", "binary" + - "value == 'binary'" + - For ASCII characters, RQL serializes the binary value like a string, + with quotes. For non-printable characters, + RQL serializes the binary to a base 64 value. + + * - :ref:`Collection ` + - "ANY items.name == {$0, $1}", "milk", "bread" + - "ANY items.name == {'milk', 'bread'}" + - Applies to collections, dictionaries, lists, and sets. Use a parameterized + value for each member of the list. + + * - RealmObject + - "ANY items == $0", obj("Item", oid(6489f036f7bd0546377303ab)) + - "ANY items == obj('Item', oid(6489f036f7bd0546377303ab))" + - To pass in a RealmObject, you need the class and primary key of the object. + +.. _rql-dot-notation: + Dot Notation ~~~~~~~~~~~~ .. TODO: add bracket notation to example -You can use **dot notation** to refer to child properties of an object, including the properties of embedded objects and relationships: +You can use **dot notation** to refer to child properties of an object, +including the properties of embedded objects and relationships: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst @@ -206,9 +210,9 @@ Nil Type ~~~~~~~~ Realm Query Language includes the ``nil`` type to represent a null pointer. -You can either reference ``nil`` directly in your queries or with a parameterized query. -If you're using a parameterized query, each SDK maps its respective null pointer -to ``nil``. +You can either reference ``nil`` directly in your queries or with a +parameterized query. If you're using a parameterized query, each SDK maps its +respective null pointer to ``nil``. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst @@ -218,7 +222,6 @@ to ``nil``. General Operators ----------------- - .. _rql-comparison-operators: Comparison Operators @@ -239,18 +242,24 @@ are compared :wikipedia:`lexicographically `. is between or equal to the right-hand expression (``Y``) range. * - | ``==``, ``=`` - - Evaluates to ``true`` if the left-hand expression is equal to the right-hand expression. + - Evaluates to ``true`` if the left-hand expression is equal to the + right-hand expression. * - | ``>`` - - Evaluates to ``true`` if the left-hand expression is greater than the right-hand expression. For dates, this evaluates to ``true`` if the left-hand date is later than the right-hand date. + - Evaluates to ``true`` if the left-hand expression is greater than the + right-hand expression. For dates, this evaluates to ``true`` if the + left-hand date is later than the right-hand date. * - | ``>=`` - - Evaluates to ``true`` if the left-hand expression is greater than or equal to the right-hand expression. For dates, this evaluates to ``true`` if the left-hand date is later than or the same as the right-hand date. + - Evaluates to ``true`` if the left-hand expression is greater than or + equal to the right-hand expression. For dates, this evaluates to + ``true`` if the left-hand date is later than or the same as the + right-hand date. * - | ``IN`` - Evaluates to ``true`` if the left-hand expression is in the right-hand list. This is equivalent to and used as a shorthand - for ``== ANY`` :ref:`collection operator `. + for ``== ANY`` :ref:`collection operator `. * - | ``<`` - Evaluates to ``true`` if the left-hand numerical or date expression @@ -258,7 +267,9 @@ are compared :wikipedia:`lexicographically `. * - | ``<=`` - Evaluates to ``true`` if the left-hand numeric expression is less than - or equal to the right-hand numeric expression. For dates, this evaluates to ``true`` if the left-hand date is earlier than or the same as the right-hand date. + or equal to the right-hand numeric expression. For dates, this evaluates + to ``true`` if the left-hand date is earlier than or the same as the + right-hand date. * - | ``!=``, ``<>`` - Evaluates to ``true`` if the left-hand expression is not equal @@ -299,13 +310,16 @@ Use logical operators to create compound predicates. * - Operator - Description - * - | ``AND`` | ``&&`` + * - | ``AND`` + | ``&&`` - Evaluates to ``true`` if both left-hand and right-hand expressions are ``true``. - * - | ``NOT`` | ``!`` + * - | ``NOT`` + | ``!`` - Negates the result of the given expression. - * - | ``OR`` | ``||`` + * - | ``OR`` + | ``||`` - Evaluates to ``true`` if either expression returns ``true``. The following example uses logical operators to combine multiple predicates: @@ -375,7 +389,7 @@ Use aggregate operators to traverse a collection and reduce it to a single value * - | ``@sum`` - Evaluates to the sum of a given numerical property across a collection. - ``null`` values are ignored. + ``null`` values are ignored. The following example uses aggregate operators to find projects whose ``items`` collection property meets certain criteria: @@ -399,9 +413,11 @@ are applied in the order they appear in the query. - Description * - ``SORT`` (``ASC`` or ``DESC``) - - Sort the results collection by the specified property or properties, either in ascending (``ASC``) or descending + - Sort the results collection by the specified property or properties, + either in ascending (``ASC``) or descending (``DESC``) order. Separate multiple properties by comma and define the - sort order for each property. The SDK applies each sort operation one at a time, in order. + sort order for each property. The SDK applies each sort operation one at + a time, in order. * - ``DISTINCT`` - Remove duplicates of the specified property or properties from the @@ -418,11 +434,11 @@ The following example finds all incomplete items, then shapes the returned resul .. important:: Order Matters - The SDK executes queries in order. This includes the order of any ``SORT``, ``DISTINCT``, and ``LIMIT`` operators in - the query *and* the order of any properties within those operators. - This can greatly impact the results returned. For example, sorting a query - before limiting it can return very different results than sorting *after* - limiting it. + The SDK executes queries in order. This includes the order of any ``SORT``, + ``DISTINCT``, and ``LIMIT`` operators in the query *and* the order of any + properties within those operators. This can greatly impact the results + returned. For example, sorting a query before limiting it can return very + different results than sorting *after* limiting it. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst @@ -471,7 +487,9 @@ Type Operator Check the data type of a mixed type or dictionary property using the ``@type`` operator. Evaluate the property against a string representation of the -data type name using string comparison operators. For information on how each SDK language's data types map to database-specific data types, refer to :ref:`sdks-data-types`. +data type name using string comparison operators. For information on how each +SDK language's data types map to database-specific data types, refer to +:ref:`sdks-supported-data-types`. .. list-table:: :header-rows: 1 @@ -481,7 +499,9 @@ data type name using string comparison operators. For information on how each SD - Description * - ``@type`` - - Check if type of a mixed type or dictionary property is the specified data type represented as a string. + - Check if type of a mixed type or dictionary property is the specified + data type represented as a string. + Use ``==`` and ``!=`` to compare equality. The following example uses the ``@type`` operator to find projects @@ -526,9 +546,10 @@ based on dictionary keys and values. * - ``ALL | ANY | NONE .@type`` - Checks if the dictionary contains properties of certain type. -The following example uses dictionary operators with comparison operators to find projects based on the ``comments`` dictionary property: +The following example uses dictionary operators with comparison operators to +find projects based on the ``comments`` dictionary property: - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst .. _rql-string-operators: @@ -565,9 +586,9 @@ to filter objects based on string values. SDKs evaluate string values * - | ``LIKE`` - Evaluates to ``true`` if the left-hand string - matches the right-hand string wildcard string. A wildcard string expression is a string - that uses normal characters with two special wildcard - characters: + matches the right-hand string wildcard string. A wildcard string + expression is a string that uses normal characters with two special + wildcard characters: - The ``*`` wildcard matches zero or more of any character - The ``?`` wildcard matches any character. @@ -581,7 +602,7 @@ to filter objects based on string values. SDKs evaluate string values The following example uses string and comparison operators to find projects based on the project name: - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst .. tip:: String Values are Case Sensitive @@ -636,7 +657,8 @@ lists and comparison operators: * - ``ANY {1, 2, 3} > ALL {1, 2}`` - true - - A value on the left (3) is greater than some value on the right (both 1 and 2) + - A value on the left (3) is greater than some value on the right (both 1 + and 2) * - ``ANY {1, 2, 3} == NONE {1, 2}`` - true @@ -680,7 +702,8 @@ lists and comparison operators: ObjectId and UUID Queries ~~~~~~~~~~~~~~~~~~~~~~~~~ -Use :ref:`comparison operators ` to compare :manual:`BSON ObjectIds ` and +Use :ref:`comparison operators ` to compare +:manual:`BSON ObjectIds ` and :manual:`UUIDs ` for equality. These data types are often used as primary keys. @@ -700,7 +723,8 @@ arguments or to the ``oid()`` or ``uuid()`` predicate functions, respectively. * - | ``uuid()`` - The string representation of the ``UUID`` to evaluate. -The following examples use equality comparison operators to find items based on their ``_id`` property: +The following examples use equality comparison operators to find items based on +their ``_id`` property: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst @@ -718,17 +742,20 @@ Specify dates in the following formats: (year-month-day@hours:minutes:seconds:nanoseconds), UTC. - As a time in seconds since the :wikipedia:`Unix epoch `: ``Ts:n`` - (``T`` designates the start of the time, ``s`` is the number of seconds, and ``n`` is the number of nanoseconds). + (``T`` designates the start of the time, ``s`` is the number of seconds, and + ``n`` is the number of nanoseconds). .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst -The following example uses a parameterized query to find items based on a new ``dateCreated`` property that populates when an item is marked as complete: +The following example uses a parameterized query to find items based on a new +``dateCreated`` property that populates when an item is marked as complete: - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rest +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst .. tip:: Parameterize Date Queries - We recommend using a parameterized query to pass the date data type from the SDK language you are using to your query. + We recommend using a parameterized query to pass the date data type from + the SDK language you are using to your query. .. _rql-backlinks: @@ -753,7 +780,8 @@ corresponding backlink. property name (``@links..``). * - ``@count`` - The number of elements in a backlink collection. You can use the - ``@count`` operator directly on ``@links`` to query the count of all relationships that point to an object. + ``@count`` operator directly on ``@links`` to query the count of all + relationships that point to an object. You can access backlinks: @@ -763,14 +791,18 @@ You can access backlinks: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst -- Using the ``linkingObjects`` property to explicitly include the backlink in your data model. This lets you reference the backlink through an assigned property name using :ref:`dot notation `. +- Using the ``linkingObjects`` property to explicitly include the backlink in + your data model. This lets you reference the backlink through an assigned + property name using :ref:`dot notation `. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst The result of a backlink is treated like a collection and supports -:ref:`collection operators ` and :ref:`aggregate operators `. +:ref:`collection operators ` and +:ref:`aggregate operators `. -The following examples find items based on the projects they belong to through the ``@links`` operator or the ``projects`` property: +The following examples find items based on the projects they belong to through +the ``@links`` operator or the ``projects`` property: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst @@ -792,9 +824,9 @@ search (FTS) annotation. For information on enabling FTS on a property, refer to * - ``TEXT`` - Evaluates to ``true`` if the left-hand FTS-enabled string property - matches the right-hand string or wildcard string. A wildcard string expression is a string - that uses normal characters with two special wildcard - characters: + matches the right-hand string or wildcard string. A wildcard string + expression is a string that uses normal characters with two special + wildcard characters: - The ``*`` wildcard matches zero or more of any character that occur after the string. @@ -802,8 +834,10 @@ search (FTS) annotation. For information on enabling FTS on a property, refer to Query strings are converted to tokens by a tokenizer using the following rules: -- Tokens can only consist of characters from ASCII and the Latin-1 supplement (western languages). All other characters are considered whitespace. -- Strings split by a hyphen (``-``) are split into two tokens. For example, ``full-text`` splits into ``full`` and ``text``. +- Tokens can only consist of characters from ASCII and the Latin-1 supplement + western languages). All other characters are considered whitespace. +- Strings split by a hyphen (``-``) are split into two tokens. For example, + ``full-text`` splits into ``full`` and ``text``. - Tokens are diacritics insensitive and case insensitive. You can search for entire words or phrases, or limit your results with the @@ -813,8 +847,8 @@ following wildcard characters: - Specify prefixes by placing the ``*`` wildcard at the end of a prefix. Suffix searching is not currently supported. -The following example uses the ``TEXT`` operator to find items based on their FTS-enabled -``name`` property: +The following example uses the ``TEXT`` operator to find items based on their +FTS-enabled ``name`` property: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst @@ -834,18 +868,21 @@ defining geospatial data, refer to :ref:`sdks-define-geospatial-object`. - Description * - ``geoWithin`` - - Returns objects where the latitude/longitude pair in a custom embedded object's ``coordinates`` property + - Returns objects where the latitude/longitude pair in a custom embedded + object's ``coordinates`` property is contained within a specified geospatial shape. - The following geospatial shapes are supported: - - ``GeoCircle`` - - ``GeoBox`` - - ``GeoPolygon`` + The following geospatial shapes are supported: + + - ``GeoCircle`` + - ``GeoBox`` + - ``GeoPolygon`` A geospatial query consists of: - An object with a property containing the embedded geospatial data. - A defined geospatial shape to set the boundary for the query: + - ``GeoCircle`` - ``GeoBox`` - ``GeoPolygon`` @@ -853,16 +890,16 @@ A geospatial query consists of: The query evaluates ``true`` if the coordinates of the embedded property are within the boundaries of the geospatial shape. -The following example compares the coordinates of -the embedded ``location`` property against the boundaries of the ``GeoCircle`` -shape named +The following example compares the coordinates of the embedded ``location`` +property against the boundaries of the ``GeoCircle`` shape named ``smallCircle``: -.. include:: /examples/generated/node/v12/geospatial.test.snippet.rql-geospatial.ts.rst +.. include:: /examples/generated/node/v12/formatted/geospatial.test.snippet.rql-geospatial.js.rst .. important:: Geospatial Queries Do Not Support Parameterized Queries - You cannot use :ref:`parameterized queries ` with geospatial data. + You cannot use :ref:`parameterized queries ` with + geospatial data. .. _rql-subqueries: @@ -892,11 +929,13 @@ Subqueries use the following syntax: must be a list of objects, not a list of primitive types. - ``variableName``: A variable name of the element to use in the subquery, prefixed with ``$``. - - ``predicate``: The subquery predicate. Use the variable specified by ``variableName`` to refer to the currently-iterated element. + - ``predicate``: The subquery predicate. Use the variable specified by + ``variableName`` to refer to the currently-iterated element. * - ``@count`` - The number of objects in the subquery results collection. This is - required for subquery filters. You can use the count of the subquery result as you would any other number in a valid expression. + required for subquery filters. You can use the count of the subquery + result as you would any other number in a valid expression. The following example uses subquery filters to find projects based on the ``items`` collection property using the ``$item`` variable name: @@ -906,7 +945,8 @@ The following example uses subquery filters to find projects based on the .. tip:: Compare Count to ``0`` to Return All Matching Objects The ``@count`` aggregate operator returns the number of objects in the - subquery results collection. You can compare the count with the number ``0`` to return all matching objects. + subquery results collection. You can compare the count with the number ``0`` + to return all matching objects. .. _flexible-sync-rql-limitations: From 59367c7c23cbf1da5c83a9bfb8c25f6c4674b1ef Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 18 Jul 2024 12:38:37 -0400 Subject: [PATCH 10/12] Apply feedback --- .../__tests__/realm-query-language.test.ts | 174 +++-- .../query/rql-example-data-model.rst | 24 +- .../query-engines/realm-query-language.txt | 647 ++++++++++-------- 3 files changed, 479 insertions(+), 366 deletions(-) diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts index 4b56fcfe0e..260e6afc02 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.ts +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -170,7 +170,7 @@ describe("Realm Query Language Reference", () => { // NOTE: snippet used on Node.js Query Data page, not RQL page // :snippet-start: simple-query const items = realm.objects(Item); - // Get all items where 'priority' property is 7 or more. + // Get all items where 'priority' property is 7 or more const importantItems = items.filtered("priority >= $0", 7); // :snippet-end: expect(importantItems.length).toEqual(5); @@ -179,8 +179,11 @@ describe("Realm Query Language Reference", () => { describe("Basic syntax", () => { test("Expression query", () => { const items = realm.objects(Item); - // :snippet-start: predicate - const expression = "priority == 1"; + // prettier-ignore + const expression = + // :snippet-start: predicate + "priority == 1" + ; // :remove: // Property Name: priority // Operator: == // Value: 1 @@ -201,7 +204,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const substitution = items.filtered( // :snippet-start: parameterized-query - // Include one parameter with `$0`. + // Include one parameter with `$0` "progressMinutes > 1 AND assignee == $0", "Ali" // :remove-start: @@ -214,7 +217,8 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const substitution = items.filtered( // :remove-end: - // Include multiple parameters using ascending integers, starting at`$0`. + // Include multiple parameters using ascending integers, + // starting at`$0` "progressMinutes > $0 AND assignee == $1", 1, "Alex" // :snippet-end: ); @@ -225,13 +229,15 @@ describe("Realm Query Language Reference", () => { const address = realm.objects(Project); const nestedItem = address.filtered( // :snippet-start: dot-notation - // Find projects whose `items` list property contains an item with a specific name. + // Find projects whose `items` list property contains an item + // with a specific name "items[0].name == 'Approve project plan'" // :snippet-end: ); const nestedZipcode = address.filtered( // :snippet-start: deep-dot-notation - // Find projects whose `projectLocation` property contains an embedded Address object with a specific zip code. + // Find projects whose `projectLocation` property contains an + // embedded Address object with a specific zip code "projectLocation.address.zipcode == 10019" // :snippet-end: ); @@ -246,7 +252,7 @@ describe("Realm Query Language Reference", () => { const highPriorityItems = items.filtered( // :snippet-start: comparison-operators - // Compare `priority` values against a threshold value. + // Compare `priority` values against a threshold value "priority > $0", 5 // :remove-start: @@ -264,7 +270,7 @@ describe("Realm Query Language Reference", () => { const progressMinutesRange = items.filtered( // :remove-end: - // Compare `priority` values against an inclusive range of values. + // Compare `priority` values against an inclusive range of values "priority BETWEEN { $0 , $1 }", 1, 5 // :remove-start: @@ -273,7 +279,7 @@ describe("Realm Query Language Reference", () => { const progressMinutesIn = items.filtered( // :remove-end: - // Compare `progressMinutes` values against any of the listed values. + // Compare `progressMinutes` values against any of the listed values "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 // :snippet-end: ); @@ -284,14 +290,14 @@ describe("Realm Query Language Reference", () => { const items = realm.objects(Item); const aliComplete = items.filtered( // :snippet-start: logical-operators - // Find all items assigned to Ali AND marked completed. + // Find all items assigned to Ali AND marked completed "assignee == $0 AND isComplete == $1", "Ali", true // :remove-start: ); const alexOrAli = items.filtered( // :remove-end: - // Find all items assigned to Alex OR to Ali. + // Find all items assigned to Alex OR to Ali "assignee == $0 OR assignee == $1", "Alex", "Ali" // :snippet-end: ); @@ -305,13 +311,13 @@ describe("Realm Query Language Reference", () => { const basicMath = items.filtered( // :snippet-start: basic-arithmetic // Evaluate against an item's `priority` property value: - "2 * priority > 6" // resolves to `priority > 3` + "2 * priority > 6" // (resolves to `priority > 3`) // :remove-start: ); const lessBasicMath = items.filtered( // :remove-end: - "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` + "priority >= 2 * (2 - 1) + 2" // (resolves to `priority >= 4`) // :remove-start: ); @@ -337,7 +343,8 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects(Project); const startWithE = projects.filtered( // :snippet-start: string-operators - // Find projects whose name starts with 'E' or 'e' (case-insensitive). + // Find projects whose name starts with 'E' or 'e' + // (case-insensitive query) "name BEGINSWITH[c] $0", "E" // :remove-start: @@ -346,7 +353,8 @@ describe("Realm Query Language Reference", () => { const containIe = projects.filtered( // :remove-end: - // Find projects whose name contains 'ie' (case-sensitive). + // Find projects whose name contains 'ie' + // (case-sensitive query) "name CONTAINS $0", "ie" // :remove-start: @@ -360,7 +368,8 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const assigneeBetween = items.filtered( // :remove-end: - // Find items where the assignee name is lexicographically between 'Ali' and 'Chris' (case-sensitive). + // Find items where the assignee name is lexicographically between + // 'Ali' and 'Chris'(case-sensitive) "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" // :remove-start: @@ -368,7 +377,8 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const compareStreet = projects.filtered( // :remove-end: - // Find projects where the street address is lexicographically greater than '123 Main St' (case-sensitive). + // Find projects where the street address is lexicographically + // greater than '123 Main St'(case-sensitive) "projectLocation.address.street > $0", "123 Main St" // :snippet-end: ); @@ -386,7 +396,7 @@ describe("Realm Query Language Reference", () => { // :remove-start: const averageItemPriorityAbove5 = projects.filtered( // :remove-end: - // Find projects with average item `priority` above 5. + // Find projects with average item `priority` above 5 "items.@avg.priority > $0", priorityNum // :remove-start: @@ -395,7 +405,7 @@ describe("Realm Query Language Reference", () => { const allItemsLowerPriority = projects.filtered( // :remove-end: - // Find projects where maximum `priority` of all items is 5. + // Find projects where maximum `priority` of all items is 5 "items.@max.priority < $0", priorityNum // :remove-start: @@ -404,7 +414,7 @@ describe("Realm Query Language Reference", () => { const allItemsHighPriority = projects.filtered( // :remove-end: - // Find projects where minimum `priority` of all items is 5. + // Find projects where minimum `priority` of all items is 5 "items.@min.priority > $0", priorityNum // :remove-start: @@ -413,8 +423,7 @@ describe("Realm Query Language Reference", () => { const moreThan5Items = projects.filtered( // :remove-end: - - // Find projects with more than 5 items. + // Find projects with more than 5 items "items.@count > $0", 5 // :remove-start: @@ -423,7 +432,7 @@ describe("Realm Query Language Reference", () => { const longRunningProjects = projects.filtered( // :remove-end: - // Find projects with item `progressMinutes` greater than 100. + // Find projects with item `progressMinutes` greater than 100 "items.@sum.progressMinutes > $0", 100 // :snippet-end: ); @@ -436,7 +445,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const noCompleteItems = projects.filtered( // :snippet-start: set-operators - // Find projects with no complete items. + // Find projects with no complete items "NONE items.isComplete == $0", true // :remove-start: @@ -444,15 +453,15 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const anyTopPriorityItems = projects.filtered( // :remove-end: - // Find projects that contain any item with priority 10. - "items.priority == $0", 10 // (ANY operator is implied.) + // Find projects that contain any item with priority 10 + "items.priority == $0", 10 // (ANY operator is implied) // :remove-start: ); // prettier-ignore const allItemsCompleted = projects.filtered( // :remove-end: - // Find projects that only contain completed items. + // Find projects that only contain completed items "ALL items.isComplete == $0", true // :remove-start: @@ -460,7 +469,8 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const assignedToAlexOrAli = projects.filtered( // :remove-end: - // Find projects with at least one item assigned to either Alex or Ali. + // Find projects with at least one item assigned to + // either Alex or Ali "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" // :remove-start: @@ -468,7 +478,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const notAssignedToAlexOrAli = projects.filtered( // :remove-end: - // Find projects with no items assigned to either Alex or Ali. + // Find projects with no items assigned to either Alex or Ali "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" // :snippet-end: ); @@ -486,13 +496,15 @@ describe("Realm Query Language Reference", () => { const collectionQuery = projects.filtered( // :snippet-start: list-comparisons-collection - // Find an item with the specified ObjectId value in the `items` collection. + // Find an item with the specified ObjectId value + // in the`items` collection "oid(631a072f75120729dc9223d9) IN items._id" // :snippet-end: ); const staticQuery = items.filtered( // :snippet-start: list-comparisons-static - // Find items with a priority value matching any value in the static list. + // Find items with a priority value matching any value + // in the static list "priority IN {0, 1, 2}" // :snippet-end: ); @@ -502,7 +514,8 @@ describe("Realm Query Language Reference", () => { new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; - // Find items with an ObjectId value matching any value in the parameterized list. + // Find items with an ObjectId value matching any value + // in the parameterized list const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); // :snippet-end: @@ -516,7 +529,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const equivalentAnyOperator = items.filtered( // :remove-end: - "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) + "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied) // :snippet-end: ); @@ -532,8 +545,9 @@ describe("Realm Query Language Reference", () => { const sortedItems = items.filtered( // :snippet-start: sort-distinct-limit - // Find incomplete items, sort by `priority` in descending order, then - // sort equal `priority` values by `progressMinutes` in ascending order. + // Find incomplete items, sort by `priority` in descending order, + // then sort equal `priority` values by `progressMinutes` + // in ascending order "isComplete == false SORT(priority DESC, progressMinutes ASC)" // :remove-start: @@ -542,7 +556,7 @@ describe("Realm Query Language Reference", () => { const distinctItems = items.filtered( // :remove-end: // Find high priority items, then remove from the results any items - // with duplicate values for both `name` AND `assignee` properties. + // with duplicate values for both `name` AND `assignee` properties "priority >= 5 DISTINCT(name, assignee)" // :remove-start: @@ -550,7 +564,7 @@ describe("Realm Query Language Reference", () => { expect(distinctItems.length).toBe(6); const limitItems = items.filtered( // :remove-end: - // Find in-progress items, then return the first 10 results. + // Find in-progress items, then return the first 10 results "progressMinutes > 0 && isComplete != true LIMIT(10)" // :snippet-end: ); @@ -558,18 +572,18 @@ describe("Realm Query Language Reference", () => { const sortFirst = items.filtered( // :snippet-start: sort-distinct-limit-order-matters - // 1. Sorts by highest priority. - // 2. Returns the first item. - // 3. Remove duplicate names (N/A because a single item is always considered distinct). + // 1. Sorts by highest priority + // 2. Returns the first item + // 3. Remove duplicate names (N/A - a single item is always distinct) "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" // :remove-start: ); const limitLast = items.filtered( // :remove-end: - // 1. Removes any duplicates by name. - // 2. Sorts by highest priority. - // 3. Returns the first item. + // 1. Removes any duplicates by name + // 2. Sorts by highest priority + // 3. Returns the first item "assignee == null DISTINCT(name) SORT(priority ASC) LIMIT(1)" // :snippet-end: ); @@ -579,7 +593,7 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects("Project"); const subquery = projects.filtered( // :snippet-start: subquery - // Find projects with incomplete items with 'Demo' in the name. + // Find projects with incomplete items with 'Demo' in the name "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" // :remove-start: @@ -589,7 +603,8 @@ describe("Realm Query Language Reference", () => { const subquery2 = projects.filtered( // :remove-end: - // Find projects where the number of completed items is greater than or equal to the project's `quota` property. + // Find projects where the number of completed items is + // greater than or equal to the project's `quota` property "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" // :snippet-end: ); @@ -603,21 +618,24 @@ describe("Realm Query Language Reference", () => { const dictionaries = realm.objects(Project); const statusKey = dictionaries.filtered( // :snippet-start: dictionary-operators - // Find projects whose `comments` dictionary property have a key of 'status'. + // Find projects whose `comments` dictionary property + // have a key of 'status' "comments.@keys == $0", "status" // :remove-start: ); const statusOnTrack = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property have a 'status' key with a value that ends in 'track'. + // Find projects whose `comments` dictionary property + // have a 'status' key with a value that ends in 'track' "comments['status'] LIKE $0", "*track" // :remove-start: ); const numItemsInDict = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property have more than one key-value pair. + // Find projects whose `comments` dictionary property + // have more than one key-value pair "comments.@count > $0", 1 // :remove-start: @@ -625,7 +643,8 @@ describe("Realm Query Language Reference", () => { const allString = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property contains only values of type 'string'. + // Find projects whose `comments` dictionary property contains + // only values of type 'string' "ALL comments.@type == 'string'" // :remove-start: @@ -633,7 +652,8 @@ describe("Realm Query Language Reference", () => { const noInts = dictionaries.filtered( // :remove-end: - // Find projects whose `comments` dictionary property contains no values of type 'int'. + // Find projects whose `comments` dictionary property contains + // no values of type 'int' "NONE comments.@type == 'int'" // :snippet-end: ); @@ -650,7 +670,7 @@ describe("Realm Query Language Reference", () => { const atLinksResult = realm.objects(Item).filtered( // :snippet-start: backlinks-atLinks // Find items that belong to a project with a quota less than 10 - // (using '@links..'). + // (using '@links..') "@links.Project.items.quota < 10" // :snippet-end: ); @@ -658,8 +678,9 @@ describe("Realm Query Language Reference", () => { const linkingObjectsResult = realm.objects(Item).filtered( // :snippet-start: backlinks-linkingObjects - // Find items that belong to a project with a quota greater than 10 through the Item object's `projects` property - // (using 'LinkingObjects'). + // Find items that belong to a project with a quota greater than 10 + // through the Item object's `projects` property + // (using 'LinkingObjects') "projects.quota > 10" // :snippet-end: ); @@ -669,7 +690,8 @@ describe("Realm Query Language Reference", () => { test("Backlinks collection operators", () => { const anyResult = realm.objects(Item).filtered( // :snippet-start: backlinks-collection-operators - // Find items where no project that references the item has a quota greater than 10. + // Find items where no project that references the item has a + // quota greater than 10 "NONE @links.Project.items.quota > 10" // :remove-start: @@ -678,7 +700,8 @@ describe("Realm Query Language Reference", () => { const allResult = realm.objects(Item).filtered( // :remove-end: - // Find items where all projects that reference the item have a quota less than 5. + // Find items where all projects that reference the item have a + // quota less than 5 "ALL @links.Project.items.quota < 5" // :remove-start: @@ -689,7 +712,7 @@ describe("Realm Query Language Reference", () => { test("Backlinks aggregate operators", () => { const shallowResultLinkingObjects = realm.objects(Item).filtered( // :remove-end: - // Find items that are referenced by multiple projects. + // Find items that are referenced by multiple projects "projects.@count > 1" // :remove-start: @@ -699,7 +722,7 @@ describe("Realm Query Language Reference", () => { const shallowResultAtLinks = realm.objects(Item).filtered( // :remove-end: - // Find items that are not referenced by any project. + // Find items that are not referenced by any project "@links.Project.items.@count == 0" // :remove-start: @@ -709,7 +732,8 @@ describe("Realm Query Language Reference", () => { const deepResultAtLinks = realm.objects(Item).filtered( // :remove-end: - // Find items that belong to a project where the average item has been worked on for at least 10 minutes + // Find items that belong to a project where the average item + // has been worked on for at least 10 minutes "@links.Project.items.items.@avg.progressMinutes > 10" // :remove-start: @@ -721,7 +745,8 @@ describe("Realm Query Language Reference", () => { test("Count all backlinks (@links.@count)", () => { const result = realm.objects(Item).filtered( // :remove-end: - // Find items that are not referenced by another object of any type (backlink count is 0). + // Find items that are not referenced by another object + // of any type (backlink count is 0) "@links.@count == 0" // :snippet-end: ); @@ -735,7 +760,7 @@ describe("Realm Query Language Reference", () => { const projects = realm.objects(Project); const mixedString = projects.filtered( // :snippet-start: type-operator - // Find projects with an `additionalInfo` property of string type. + // Find projects with an `additionalInfo` property of string type "additionalInfo.@type == 'string'" // :remove-start: @@ -743,14 +768,15 @@ describe("Realm Query Language Reference", () => { const mixedCollection = projects.filtered( // :remove-end: // Find projects with an `additionalInfo` property of - // `collection` type, which matches list or dictionary types. + // `collection` type, which matches list or dictionary types "additionalInfo.@type == 'collection'" // :remove-start: ); const mixedBool = projects.filtered( // :remove-end: - // Find projects with an `additionalInfo` property of list type, where any list element is of type 'bool'. + // Find projects with an `additionalInfo` property of list type, + // where any list element is of type 'bool' "additionalInfo[*].@type == 'bool'" // :snippet-end: ); @@ -769,7 +795,7 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const res2 = realm.objects(Item).filtered( // :remove-end: - "assignee == $0", null // 'null' maps to the SDK language's null pointer + "assignee == $0", null // 'null' maps to SDK language's null pointer // :snippet-end: ); expect(res.length).toBe(1); @@ -818,7 +844,8 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const oidStringLiteral = oidUuids.filtered( // :snippet-start: oid - // Find an item whose `_id` matches the ObjectID value passed to 'oid()'. + // Find an item whose `_id` matches the ObjectID value + // passed to 'oid()' "_id == oid(6001c033600510df3bbfd864)" // :remove-start: @@ -826,7 +853,8 @@ describe("Realm Query Language Reference", () => { const oidInterpolation = oidUuids.filtered( // :remove-end: - // Find an item whose `_id` matches the ObjectID passed as a parameterized query argument. + // Find an item whose `_id` matches the ObjectID passed as + // a parameterized query argument "_id == $0", oidValue // :remove-start: @@ -839,7 +867,8 @@ describe("Realm Query Language Reference", () => { const oidUuids = realm.objects("OidUuid"); const uuid = oidUuids.filtered( // :remove-end: - // Find an item whose `id` matches the UUID value passed to 'uuid()'. + // Find an item whose `id` matches the UUID value + // passed to 'uuid()' "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" // :remove-start: @@ -847,7 +876,8 @@ describe("Realm Query Language Reference", () => { // prettier-ignore const test = oidUuids.filtered( // :remove-end: - // Find an item whose `_id` matches the UUID passed as a parameterized query argument. + // Find an item whose `_id` matches the UUID passed as + // a parameterized query argument "id == $0", uuidValue // :snippet-end: ); @@ -903,7 +933,7 @@ describe("Realm Query Language Reference", () => { // :snippet-end: const dateParameterizedQuery = dates.filtered( // :snippet-start: date-parameterized-query - // Find to-do items completed before today's date. + // Find to-do items completed before today's date "dateCompleted < $0", today // :remove-start: @@ -911,7 +941,7 @@ describe("Realm Query Language Reference", () => { const dateAlt1 = dates.filtered( // :remove-end: - // Find to-do items completed between the start of the year until today. + // Find to-do items completed between start of the year to today "dateCompleted > $0 AND dateCompleted < $1", thisYear, today // :snippet-end: ); @@ -936,7 +966,7 @@ describe("Realm Query Language Reference", () => { const itemsWithWriteNotTest = items.filtered( // :remove-end: // Use '-' to exclude: - // Find items with 'write' but not 'tests' in the name. + // Find items with 'write' but not 'tests' in the name "name TEXT $0", "write -tests" // :remove-start: @@ -945,7 +975,7 @@ describe("Realm Query Language Reference", () => { const itemsStartingWithWri = items.filtered( // :remove-end: // Use '*' to match any characters after a prefix: - // Find items with a name that starts with 'wri'. + // Find items with a name that starts with 'wri' "name TEXT $0", "wri*" // :snippet-end: ); diff --git a/source/includes/sdk-examples/query/rql-example-data-model.rst b/source/includes/sdk-examples/query/rql-example-data-model.rst index f7e9d65642..8cec6893b2 100644 --- a/source/includes/sdk-examples/query/rql-example-data-model.rst +++ b/source/includes/sdk-examples/query/rql-example-data-model.rst @@ -5,7 +5,7 @@ content: | .. literalinclude:: /examples/generated/cpp/filter-data.snippet.models.cpp - :language: cpp + :language: cpp-sdk - id: csharp content: | @@ -41,6 +41,28 @@ Integer quota = null; } + - id: java-kotlin + content: | + + .. code-block:: kotlin + + open class Item(): RealmObject() { + var id: ObjectId = new ObjectId() + @FullText + lateinit var name: String + var isComplete: Boolean = false + var assignee: String? = null + var priority: Int = 0 + var progressMinutes: Int = 0 + } + + open class Project(): RealmObject() { + var id: ObjectId = new ObjectId() + lateinit var name: String + lateinit var items: RealmList + var quota: Int? = null + } + - id: javascript content: | diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index 33725bf92f..563d6bd8fe 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -26,29 +26,25 @@ Realm Query Language (RQL) .. tabs-selector:: drivers Realm Query Language (RQL) is a string-based query language that you can use -to construct queries in most Atlas Device SDKs. The SDK-specific methods pass -the queries -to the Realm database query engine, which retrieves matching database objects. +to construct queries for Atlas Device SDK. Each SDK provides language-specific +filter or query methods that pass the queries to the Realm database query +engine. For more information about SDK-specific query methods, refer to +:ref:`sdks-crud-read`. .. important:: Swift SDK Does Not Support Realm Query Language (RQL) The Swift SDK does *not* support querying with Realm Query Language. - Instead, it uses NSPredicate to query a database. For more information, refer to :ref:`Type-Safe and NSPredicate Queries (Swift SDK) `. - -With the exception of the Swift SDK, you can use Realm Query Language with your -preferred SDK's filter or query methods. For more information, refer to -:ref:`sdks-crud-read`. + Instead, it uses NSPredicate to query a database. For more information, refer + to :ref:`Type-Safe and NSPredicate Queries (Swift SDK) `. The following SDKs also support language-specific idiomatic APIs for querying databases: - :ref:`Fluent Interface (Java SDK) ` - :ref:`LINQ (.NET SDK) ` -- :ref:`Type-Safe and NSPredicate Queries (Swift SDK) ` -You can also use Realm Query Language to browse for data in -:ref:`Realm Studio `. Realm Studio is a visual tool -to view, edit, and design ``.realm`` database files. +In addition to using RQL in your client code, you can also use RQL in +:ref:`Realm Studio ` to browse for data. Examples on This Page --------------------- @@ -59,8 +55,8 @@ that include the following database object types: - ``Item``: Each item object has a name, assignee's name, and completed flag. There is also an arbitrary number for priority (where higher is more important) and a count of minutes spent working on it. -- ``Project``: Each project object has zero or more ``Items`` and an optional quota - for minimum number of to-do items expected to be completed. +- ``Project``: Each project object has zero or more ``Items`` and an optional + quota for minimum number of to-do items expected to be completed. .. include:: /includes/sdk-examples/query/rql-example-data-model.rst @@ -72,7 +68,8 @@ Realm Query Language syntax is based on `NSPredicate `__. Queries evaluate a predicate for every object in the collection being queried. -If the predicate resolves to ``true``, the results collection includes the object. +If the predicate resolves to ``true``, the results collection includes the +object. Realm Query Language uses expressions and predicates to filter objects. Filters consist of expressions within a predicate that evaluate to ``true`` or @@ -80,11 +77,13 @@ consist of expressions within a predicate that evaluate to ``true`` or Each expression contains the following elements: -- The name of the object property to evaluate. -- An operator and *up to two* argument expressions. For example, in the - expression ``A + B``, the entirety of ``A + B`` is an expression, but ``A`` - and ``B`` are also argument expressions to the operator ``+``. -- A value, such as a string (``'hello'``) or a number (``5``). +- **Property name**: The name of the object property to evaluate. +- **Operator** and **argument expression**: A valid operator and *up to two* + argument expressions. For example, in the expression ``A + B``, the entirety + of ``A + B`` is an expression, but ``A`` and ``B`` are also argument + expressions to the operator ``+``. +- **Value**: The value, such as a string (``'hello'``) or a number (``5``), to + use in the evaluation. .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst @@ -129,7 +128,8 @@ parameterized for the specific data types: * - :ref:`Nil ` - "assignee == $0", null - "assignee == nil" - - For parameterized queries, ``nill`` maps to each SDK's respective null pointer. + - For parameterized queries, ``nill`` maps to each SDK's respective null + pointer. * - Boolean - "setting == $0", false @@ -144,14 +144,16 @@ parameterized for the specific data types: * - :ref:`Number ` - "age > $0", 5.50 - "age > 5.50" - - Applies to ``int``, ``short``, ``long``, ``double``, ``Decimal128``, and ``float`` data types. + - Applies to ``int``, ``short``, ``long``, ``double``, ``Decimal128``, and + ``float`` data types. * - :ref:`Date ` - "date < $0", dateObject - "date < 2021-02-20\@17:30:15:0" - For parameterized queries, you must pass in a date object. For serialized queries, the representation can be a - :ref:`supported Date format ` or a parameterized ``Date`` object. + :ref:`supported Date format ` or a parameterized + ``Date`` object. * - :ref:`ObjectID ` - "_id == $0", oidValue @@ -181,15 +183,14 @@ parameterized for the specific data types: * - RealmObject - "ANY items == $0", obj("Item", oid(6489f036f7bd0546377303ab)) - "ANY items == obj('Item', oid(6489f036f7bd0546377303ab))" - - To pass in a RealmObject, you need the class and primary key of the object. + - To pass in a RealmObject, you need the class and primary key of the + object. .. _rql-dot-notation: Dot Notation ~~~~~~~~~~~~ -.. TODO: add bracket notation to example - You can use **dot notation** to refer to child properties of an object, including the properties of embedded objects and relationships: @@ -222,6 +223,76 @@ respective null pointer to ``nil``. General Operators ----------------- +.. _rql-aggregate-operators: + +Aggregate Operators +~~~~~~~~~~~~~~~~~~~ + +Use aggregate operators to traverse a collection and reduce it to a single +value. + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Operator + - Description + + * - | ``@avg`` + - Evaluates to the average value of a given numerical property across + a collection. ``null`` values are ignored. + + * - | ``@count`` + - Evaluates to the number of objects in the given collection. + + * - | ``@max`` + - Evaluates to the highest value of a given numerical property + across a collection. ``null`` values are ignored. + + * - | ``@min`` + - Evaluates to the lowest value of a given numerical property + across a collection. ``null`` values are ignored. + + * - | ``@sum`` + - Evaluates to the sum of a given numerical property across a collection. + ``null`` values are ignored. + +The following example uses aggregate operators to find projects whose ``items`` +collection property meets certain criteria: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst + +.. _rql-arithmetic-operators: + +Arithmetic Operators +~~~~~~~~~~~~~~~~~~~~ + +Use arithmetic operators to perform basic arithmetic in an expression when +evaluating numeric data types, including object properties. + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Operator + - Description + + * - | ``*`` + - Multiplication. + * - | ``/`` + - Division. + * - | ``+`` + - Addition. + * - | ``-`` + - Subtraction. + * - | ``()`` + - Group expressions together. + +The following example uses arithmetic operators on Item object properties +containing numeric values: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst + .. _rql-comparison-operators: Comparison Operators @@ -263,7 +334,9 @@ are compared :wikipedia:`lexicographically `. * - | ``<`` - Evaluates to ``true`` if the left-hand numerical or date expression - is less than the right-hand numerical or date expression. For dates, this evaluates to ``true`` if the left-hand date is earlier than the right-hand date. + is less than the right-hand numerical or date expression. For dates, this + evaluates to ``true`` if the left-hand date is earlier than the + right-hand date. * - | ``<=`` - Evaluates to ``true`` if the left-hand numeric expression is less than @@ -312,7 +385,8 @@ Use logical operators to create compound predicates. * - | ``AND`` | ``&&`` - - Evaluates to ``true`` if both left-hand and right-hand expressions are ``true``. + - Evaluates to ``true`` if both left-hand and right-hand expressions are + ``true``. * - | ``NOT`` | ``!`` @@ -327,108 +401,41 @@ The following example uses logical operators to combine multiple predicates: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst -.. _rql-arithmetic-operators: - -Arithmetic Operators -~~~~~~~~~~~~~~~~~~~~ - -Use arithmetic operators to perform basic arithmetic in an expression when -evaluating numeric data types, including object properties. - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Operator - - Description - - * - | ``*`` - - Multiplication. - * - | ``/`` - - Division. - * - | ``+`` - - Addition. - * - | ``-`` - - Subtraction. - * - | ``()`` - - Group expressions together. - -The following example uses arithmetic operators on Item object properties containing numeric values: - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst - - -.. _rql-aggregate-operators: - -Aggregate Operators -~~~~~~~~~~~~~~~~~~~ - -Use aggregate operators to traverse a collection and reduce it to a single value. - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Operator - - Description - - * - | ``@avg`` - - Evaluates to the average value of a given numerical property across - a collection. ``null`` values are ignored. - - * - | ``@count`` - - Evaluates to the number of objects in the given collection. - - * - | ``@max`` - - Evaluates to the highest value of a given numerical property - across a collection. ``null`` values are ignored. - - * - | ``@min`` - - Evaluates to the lowest value of a given numerical property - across a collection. ``null`` values are ignored. - - * - | ``@sum`` - - Evaluates to the sum of a given numerical property across a collection. - ``null`` values are ignored. - -The following example uses aggregate operators to find projects whose ``items`` -collection property meets certain criteria: - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst - .. _rql-sort-distinct-limit: -Sort, Distinct, and Limit Operators -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Results Operators +~~~~~~~~~~~~~~~~~ -Use sort, distinct, and limit operators to shape your query results collection. You can -combine these operators in a single query across multiple properties. Operators -are applied in the order they appear in the query. +Use the sort, distinct, and limit operators to shape your query results +collection. You can combine these operators in a single query across multiple +properties. Operators are applied in the order they appear in the query. .. list-table:: :header-rows: 1 :widths: 20 80 - * - Operator + * - Suffix - Description - * - ``SORT`` (``ASC`` or ``DESC``) - - Sort the results collection by the specified property or properties, - either in ascending (``ASC``) or descending - (``DESC``) order. Separate multiple properties by comma and define the - sort order for each property. The SDK applies each sort operation one at - a time, in order. + * - ``SORT`` + - Sort the results collection in the specified order for one or more + comma-separated properties. The SDK applies the sort operation for each + property in order, one at a time. Specify the sort order for each + property as either: + + - ``ASC`` (ascending) + - ``DESC`` (descending) * - ``DISTINCT`` - - Remove duplicates of the specified property or properties from the - results collection. Separate multiple properties by comma. The SDK - applies all distinct operations as a single AND condition, - where duplicates must match all specified properties. + - Remove duplicates of the one or more comma-separated properties from the + results collection. The SDK applies all distinct operations as a single + AND condition, where duplicates must match *all* specified properties. * - ``LIMIT`` - Limit the results collection to the specified number. -The following example finds all incomplete items, then shapes the returned results: +The following example finds all incomplete items, then shapes the returned +results: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst @@ -450,10 +457,10 @@ Type-Specific Operators Collection Operators ~~~~~~~~~~~~~~~~~~~~ -A collection operator lets you query list properties within a collection of objects. -Collection operators filter a collection by applying a predicate -to every element of a given list property of the object. -If the predicate returns true, the object is included in the output collection. +A collection operator lets you query list properties within a collection of +objects. Collection operators filter a collection by applying a predicate to +every element of a given list property of the object. If the predicate returns +true, the object is included in the output collection. .. list-table:: :header-rows: 1 @@ -480,41 +487,6 @@ collection property meets certain criteria .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst -.. _rql-type-operator: - -Type Operator -~~~~~~~~~~~~~ - -Check the data type of a mixed type or dictionary property using the -``@type`` operator. Evaluate the property against a string representation of the -data type name using string comparison operators. For information on how each -SDK language's data types map to database-specific data types, refer to -:ref:`sdks-supported-data-types`. - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Operator - - Description - - * - ``@type`` - - Check if type of a mixed type or dictionary property is the specified - data type represented as a string. - - Use ``==`` and ``!=`` to compare equality. - -The following example uses the ``@type`` operator to find projects -whose mixed data type ``additionalInfo`` property type matches specific -criteria: - -.. include:: examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst - -.. note:: Only Supported for Mixed Data Types and Dictionaries - - You can currently only use the ``@type`` operator with mixed data types and - dictionary properties. - .. _rql-dictionary-operators: Dictionary Operators @@ -597,7 +569,8 @@ to filter objects based on string values. SDKs evaluate string values "dig", and "dug", but not "ding", "dg", or "a dog". * - | ``[c]`` - - Modifier that indicates a string value is *not* case sensitive. + - Modifier that indicates a string value is *not* case sensitive. String + values are case sensitive by default. The following example uses string and comparison operators to find projects based on the project name: @@ -606,166 +579,60 @@ based on the project name: .. tip:: String Values are Case Sensitive - String values are case sensitive by default. Use the ``[c]`` modifier to specify that values are *not* case sensitive. + String values are case sensitive by default. Use the ``[c]`` modifier to + specify that values are *not* case sensitive. -Type-Specific Queries ---------------------- + For example, ``"name CONTAINS[c] $0", "da"`` would return "David" and "Ida", + but ``"name CONTAINS $0", "da"`` would only return "Ida". -.. _rql-list-queries: - -List Comparisons -~~~~~~~~~~~~~~~~ - -Use :ref:`comparison operators ` and -:ref:`collection operators ` to filter based -on lists of data. You can compare any type of valid list, including: - -- Collections of objects, which let you filter against other data - in the database. - - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst - -- Lists defined directly in the query, which let you filter against - static data. You define static lists as a comma-separated list of - literal values enclosed in opening (``{``) and closing (``}``) braces. - - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst - -- Native list objects passed in a :ref:`parameterized expression - `, which let you pass application data - directly to your queries. - - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst - -.. note:: Defaults to ``ANY`` - - If you do not define a collection operator, a list expression defaults - to the ``ANY`` operator. - - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst - -The following table demonstrates how collection operators interact with -lists and comparison operators: - -.. list-table:: - :widths: 45 10 45 - - * - Expression - - Match? - - Reason - - * - ``ANY {1, 2, 3} > ALL {1, 2}`` - - true - - A value on the left (3) is greater than some value on the right (both 1 - and 2) - - * - ``ANY {1, 2, 3} == NONE {1, 2}`` - - true - - 3 does not match either of 1 or 2 - - * - ``ANY {4, 8} == ANY {5, 9, 11}`` - - false - - Neither 4 nor 8 matches any value on the right (5, 9 or 11) - - * - ``ANY {1, 2, 7} <= NONE {1, 2}`` - - true - - A value on the left (7) is not less than or equal to both 1 and 2 - - * - ``ALL {1, 2} IN ANY {1, 2, 3}`` - - true - - Every value on the left (1 and 2) is equal to 1, 2 or 3 - - * - ``ALL {3, 1, 4, 3} == NONE {1, 2}`` - - false - - 1 matches a value in the NONE list (1 or 2) - - * - ``ALL {} in ALL {1, 2}`` - - true - - An empty list matches all lists - - * - ``NONE {1, 2, 3, 12} > ALL {5, 9, 11}`` - - false - - 12 is bigger than all values on the right (5, 9, and 11) - - * - ``NONE {4, 8} > ALL {5, 9, 11}`` - - true - - 4 and 8 are both less than some value on the right (5, 9, or 11) - - * - ``NONE {0, 1} < NONE {1, 2}`` - - true - - 0 and 1 are both less than none of 1 and 2 - +.. _rql-type-operator: -.. _rql-objectid-uuid-operators: +Type Operator +~~~~~~~~~~~~~ -ObjectId and UUID Queries -~~~~~~~~~~~~~~~~~~~~~~~~~ +.. note:: Only Supported for Mixed Data Types and Dictionaries -Use :ref:`comparison operators ` to compare -:manual:`BSON ObjectIds ` and -:manual:`UUIDs ` for equality. These data types are -often used as primary keys. + You can currently only use the ``@type`` operator with mixed data types and + dictionary properties. -You can use pass ``ObjectId`` and ``UUID`` values either as parameterized query -arguments or to the ``oid()`` or ``uuid()`` predicate functions, respectively. +Check the data type of a mixed type or dictionary property using the +``@type`` operator. Evaluate the property against a string representation of the +data type name using string comparison operators. For information on how each +SDK language's data types map to database-specific data types, refer to +:ref:`sdks-supported-data-types`. .. list-table:: :header-rows: 1 - :widths: 30 70 + :widths: 20 80 * - Operator - Description - * - | ``oid()`` - - The string representation of the ``ObjectID`` to evaluate. - - * - | ``uuid()`` - - The string representation of the ``UUID`` to evaluate. - -The following examples use equality comparison operators to find items based on -their ``_id`` property: - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst - -.. _rql-date-operators: - -Date Queries -~~~~~~~~~~~~ - -Use :ref:`comparison operators ` to query date types. - -Specify dates in the following formats: - -- As a date in UTC, with the date and time separated by ``@`` or ``T``: - ``YYYY-MM-DD@HH:mm:ss:nnnnnnnnnn`` - (year-month-day@hours:minutes:seconds:nanoseconds), UTC. -- As a time in seconds since the :wikipedia:`Unix epoch `: - ``Ts:n`` - (``T`` designates the start of the time, ``s`` is the number of seconds, and - ``n`` is the number of nanoseconds). - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst + * - ``@type`` + - Check if type of a mixed type or dictionary property is the specified + data type represented as a string. -The following example uses a parameterized query to find items based on a new -``dateCreated`` property that populates when an item is marked as complete: + Use ``==`` and ``!=`` to compare equality. -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst +The following example uses the ``@type`` operator to find projects +whose mixed data type ``additionalInfo`` property type matches specific +criteria: -.. tip:: Parameterize Date Queries +.. include:: examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst - We recommend using a parameterized query to pass the date data type from - the SDK language you are using to your query. +Type-Specific Queries +--------------------- .. _rql-backlinks: Backlink Queries ~~~~~~~~~~~~~~~~ -A **backlink** is an :ref:`inverse relationship ` link that lets -you query objects that reference another object. Backlinks use the to-one and to-many -relationships defined in your object schemas but reverse the direction. -Every relationship that you define in your schema implicitly has a +A **backlink** is an :ref:`inverse relationship ` link that +lets you query objects that reference another object. Backlinks use the to-one +and to-many relationships defined in your object schemas but reverse the +direction. Every relationship that you define in your schema implicitly has a corresponding backlink. .. list-table:: @@ -806,6 +673,38 @@ the ``@links`` operator or the ``projects`` property: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst + +.. _rql-date-operators: + +Date Queries +~~~~~~~~~~~~ + +Use :ref:`comparison operators ` to query date types. + +Specify dates in the following formats: + +- As a date in UTC, with the date and time separated by ``@`` or ``T``: + ``YYYY-MM-DD@HH:mm:ss:nnnnnnnnnn`` + (year-month-day@hours:minutes:seconds:nanoseconds), UTC. +- As a time in seconds since the :wikipedia:`Unix epoch `: + ``Ts:n`` + (``T`` designates the start of the time, ``s`` is the number of seconds, and + ``n`` is the number of nanoseconds). + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-alt-representation.ts.rst + +The following example uses a parameterized query to find items based on a new +``dateCreated`` property that populates when an item is marked as complete: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst + +.. tip:: Parameterize Date Queries + + We recommend using a :ref:`parameterized query ` + to pass the date data type from the SDK language you are using to your + query. + + .. _rql-fts: Full Text Search (FTS) Queries @@ -852,6 +751,7 @@ FTS-enabled ``name`` property: .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst + .. _rql-geospatial: Geospatial Queries @@ -901,6 +801,92 @@ property against the boundaries of the ``GeoCircle`` shape named You cannot use :ref:`parameterized queries ` with geospatial data. + +.. _rql-list-queries: + +List Comparison Queries +~~~~~~~~~~~~~~~~~~~~~~~ + +Use :ref:`comparison operators ` and +:ref:`collection operators ` to filter based +on lists of data. You can compare any type of valid list, including: + +- Collections of objects, which let you filter against other data + in the database. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst + +- Lists defined directly in the query, which let you filter against + static data. You define static lists as a comma-separated list of + literal values enclosed in opening (``{``) and closing (``}``) braces. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst + +- Native list objects passed in a :ref:`parameterized expression + `, which let you pass application data + directly to your queries. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst + +.. note:: Defaults to ``ANY`` + + If you do not define a collection operator, a list expression defaults + to the ``ANY`` operator. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst + +The following table demonstrates how collection operators interact with +lists and comparison operators: + +.. list-table:: + :widths: 45 10 45 + + * - Expression + - Match? + - Reason + + * - ``ANY {1, 2, 3} > ALL {1, 2}`` + - true + - A value on the left (3) is greater than some value on the right (both 1 + and 2) + + * - ``ANY {1, 2, 3} == NONE {1, 2}`` + - true + - 3 does not match either of 1 or 2 + + * - ``ANY {4, 8} == ANY {5, 9, 11}`` + - false + - Neither 4 nor 8 matches any value on the right (5, 9 or 11) + + * - ``ANY {1, 2, 7} <= NONE {1, 2}`` + - true + - A value on the left (7) is not less than or equal to both 1 and 2 + + * - ``ALL {1, 2} IN ANY {1, 2, 3}`` + - true + - Every value on the left (1 and 2) is equal to 1, 2 or 3 + + * - ``ALL {3, 1, 4, 3} == NONE {1, 2}`` + - false + - 1 matches a value in the NONE list (1 or 2) + + * - ``ALL {} in ALL {1, 2}`` + - true + - An empty list matches all lists + + * - ``NONE {1, 2, 3, 12} > ALL {5, 9, 11}`` + - false + - 12 is bigger than all values on the right (5, 9, and 11) + + * - ``NONE {4, 8} > ALL {5, 9, 11}`` + - true + - 4 and 8 are both less than some value on the right (5, 9, or 11) + + * - ``NONE {0, 1} < NONE {1, 2}`` + - true + - 0 and 1 are both less than none of 1 and 2 + + .. _rql-subqueries: List Subqueries @@ -948,9 +934,84 @@ The following example uses subquery filters to find projects based on the subquery results collection. You can compare the count with the number ``0`` to return all matching objects. + +.. _rql-objectid-uuid-operators: + +ObjectId and UUID Queries +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use :ref:`comparison operators ` to compare +:manual:`BSON ObjectIds ` and +:manual:`UUIDs ` for equality. These data types are +often used as primary keys. + +You can use pass ``ObjectId`` and ``UUID`` values either as parameterized query +arguments or to the ``oid()`` or ``uuid()`` predicate functions, respectively. + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Operator + - Description + + * - | ``oid()`` + - The string representation of the ``ObjectID`` to evaluate. + + * - | ``uuid()`` + - The string representation of the ``UUID`` to evaluate. + +The following examples use equality comparison operators to find items based on +their ``_id`` property: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst + + .. _flexible-sync-rql-limitations: -Flexible Sync RQL Limitations ------------------------------ +Device Sync Subscription Queries +--------------------------------- + +If your app uses Atlas :ref:`Device Sync`, you can use +Realm Query Language to construct your :ref:`sync subscription +queries`. However, App Services does not support +all RQL operators or functionality in a subscription query. + +Device Sync does *not* support the following in a subscription query: + +- :ref:`Aggregate operators ` (``@avg``, + ``@count``, ``@max``, ``@min``, or ``@sum``) +- :ref:`Results operators ` (``DISTINCT``, + ``SORT``, or ``LIMIT``) +- :ref:`List comparisons ` (for example, + ``"{'comedy', 'horror', 'suspense'} IN genres"``) +- Querying for embedded objects or links (for example, ``obj1.field == "foo"``). + +However, you can use the following: + +- You can use ``@count`` for array fields. +- You can query lists using the ``IN`` operator: + + .. code-block:: javascript + + // Query a constant list for a queryable field value + "priority IN { 1, 2, 3 }" + + // Query an array-valued queryable field for a constant value + "'comedy' IN genres" + +.. tip:: Case-Insensitive Queries Not Recommended + + Although :ref:`case-insensitive string queries` (using + the ``[c]`` modifier) are supported in sync queries, they do not use indexes + effectively and can lead to performance problems. As a result, they are not + recommended. + +Additionally, note the following if you are using an :ref:`indexed queryable +field` in your app: + +- Every query must include the indexed queryable field. +- Every query must directly compare the indexed queryable field + against a constant using an ``==`` or ``IN`` operator at least once. +- You can optionally include an ``AND`` comparison as well. -.. include:: /includes/flex-sync-limitations.rst From 1f120b55eb33f134245d232f16b00cbb451f4542 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 18 Jul 2024 21:17:09 -0400 Subject: [PATCH 11/12] Regenerate updated snippets --- ...guage.test.snippet.aggregate-operators.ts.rst | 11 +++++------ ...anguage.test.snippet.backlinks-atLinks.ts.rst | 2 +- ...snippet.backlinks-collection-operators.ts.rst | 16 ++++++++++------ ....test.snippet.backlinks-linkingObjects.ts.rst | 5 +++-- ...language.test.snippet.basic-arithmetic.ts.rst | 4 ++-- ...uage.test.snippet.comparison-operators.ts.rst | 6 +++--- ....test.snippet.date-parameterized-query.ts.rst | 4 ++-- ...anguage.test.snippet.deep-dot-notation.ts.rst | 3 ++- ...uage.test.snippet.dictionary-operators.ts.rst | 15 ++++++++++----- ...ery-language.test.snippet.dot-notation.ts.rst | 3 ++- ....snippet.equivalent-lists-any-operator.ts.rst | 2 +- ...st.snippet.list-comparisons-collection.ts.rst | 3 ++- ...snippet.list-comparisons-parameterized.ts.rst | 3 ++- ...e.test.snippet.list-comparisons-static.ts.rst | 3 ++- ...anguage.test.snippet.logical-operators.ts.rst | 4 ++-- ...m-query-language.test.snippet.nil-type.ts.rst | 2 +- .../realm-query-language.test.snippet.oid.ts.rst | 12 ++++++++---- ...guage.test.snippet.parameterized-query.ts.rst | 5 +++-- ...-query-language.test.snippet.predicate.ts.rst | 2 +- ...lm-query-language.test.snippet.rql-fts.ts.rst | 4 ++-- ...ry-language.test.snippet.set-operators.ts.rst | 13 +++++++------ ...ery-language.test.snippet.simple-query.ts.rst | 2 +- ...ppet.sort-distinct-limit-order-matters.ts.rst | 12 ++++++------ ...guage.test.snippet.sort-distinct-limit.ts.rst | 9 +++++---- ...language.test.snippet.string-operators.ts.rst | 12 ++++++++---- ...m-query-language.test.snippet.subquery.ts.rst | 5 +++-- ...ry-language.test.snippet.type-operator.ts.rst | 7 ++++--- 27 files changed, 98 insertions(+), 71 deletions(-) diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst index 711195cbdf..2562a827f3 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst @@ -2,18 +2,17 @@ var priorityNum = 5; - // Find projects with average item `priority` above 5. + // Find projects with average item `priority` above 5 "items.@avg.priority > $0", priorityNum - // Find projects where maximum `priority` of all items is 5. + // Find projects where maximum `priority` of all items is 5 "items.@max.priority < $0", priorityNum - // Find projects where minimum `priority` of all items is 5. + // Find projects where minimum `priority` of all items is 5 "items.@min.priority > $0", priorityNum - - // Find projects with more than 5 items. + // Find projects with more than 5 items "items.@count > $0", 5 - // Find projects with item `progressMinutes` greater than 100. + // Find projects with item `progressMinutes` greater than 100 "items.@sum.progressMinutes > $0", 100 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst index e877dfd1f9..7d2c811f88 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst @@ -1,5 +1,5 @@ .. code-block:: typescript // Find items that belong to a project with a quota less than 10 - // (using '@links..'). + // (using '@links..') "@links.Project.items.quota < 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst index e56bd53246..8743becabc 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst @@ -1,19 +1,23 @@ .. code-block:: typescript - // Find items where no project that references the item has a quota greater than 10. + // Find items where no project that references the item has a + // quota greater than 10 "NONE @links.Project.items.quota > 10" - // Find items where all projects that reference the item have a quota less than 5. + // Find items where all projects that reference the item have a + // quota less than 5 "ALL @links.Project.items.quota < 5" - // Find items that are referenced by multiple projects. + // Find items that are referenced by multiple projects "projects.@count > 1" - // Find items that are not referenced by any project. + // Find items that are not referenced by any project "@links.Project.items.@count == 0" - // Find items that belong to a project where the average item has been worked on for at least 10 minutes + // Find items that belong to a project where the average item + // has been worked on for at least 10 minutes "@links.Project.items.items.@avg.progressMinutes > 10" - // Find items that are not referenced by another object of any type (backlink count is 0). + // Find items that are not referenced by another object + // of any type (backlink count is 0) "@links.@count == 0" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst index 8373b6c723..8e0bf24549 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst @@ -1,5 +1,6 @@ .. code-block:: typescript - // Find items that belong to a project with a quota greater than 10 through the Item object's `projects` property - // (using 'LinkingObjects'). + // Find items that belong to a project with a quota greater than 10 + // through the Item object's `projects` property + // (using 'LinkingObjects') "projects.quota > 10" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst index 8676d1768b..982f8c6f36 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.basic-arithmetic.ts.rst @@ -1,9 +1,9 @@ .. code-block:: typescript // Evaluate against an item's `priority` property value: - "2 * priority > 6" // resolves to `priority > 3` + "2 * priority > 6" // (resolves to `priority > 3`) - "priority >= 2 * (2 - 1) + 2" // resolves to `priority >= 4` + "priority >= 2 * (2 - 1) + 2" // (resolves to `priority >= 4`) // Evaluate against multiple object property values: "progressMinutes * priority == 90" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst index 25061aab11..51e1eb6ada 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.comparison-operators.ts.rst @@ -1,13 +1,13 @@ .. code-block:: typescript - // Compare `priority` values against a threshold value. + // Compare `priority` values against a threshold value "priority > $0", 5 // Compare `assignee` values to `null` value. "assignee == $0", null - // Compare `priority` values against an inclusive range of values. + // Compare `priority` values against an inclusive range of values "priority BETWEEN { $0 , $1 }", 1, 5 - // Compare `progressMinutes` values against any of the listed values. + // Compare `progressMinutes` values against any of the listed values "progressMinutes IN { $0, $1, $2 }", 10, 30, 60 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst index 84700fcada..539fa221c0 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.date-parameterized-query.ts.rst @@ -1,7 +1,7 @@ .. code-block:: typescript - // Find to-do items completed before today's date. + // Find to-do items completed before today's date "dateCompleted < $0", today - // Find to-do items completed between the start of the year until today. + // Find to-do items completed between start of the year to today "dateCompleted > $0 AND dateCompleted < $1", thisYear, today diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst index 8ff782049e..dcb91dfabc 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.deep-dot-notation.ts.rst @@ -1,4 +1,5 @@ .. code-block:: typescript - // Find projects whose `projectLocation` property contains an embedded Address object with a specific zip code. + // Find projects whose `projectLocation` property contains an + // embedded Address object with a specific zip code "projectLocation.address.zipcode == 10019" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst index 239ef65d49..186e16929b 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dictionary-operators.ts.rst @@ -1,16 +1,21 @@ .. code-block:: typescript - // Find projects whose `comments` dictionary property have a key of 'status'. + // Find projects whose `comments` dictionary property + // have a key of 'status' "comments.@keys == $0", "status" - // Find projects whose `comments` dictionary property have a 'status' key with a value that ends in 'track'. + // Find projects whose `comments` dictionary property + // have a 'status' key with a value that ends in 'track' "comments['status'] LIKE $0", "*track" - // Find projects whose `comments` dictionary property have more than one key-value pair. + // Find projects whose `comments` dictionary property + // have more than one key-value pair "comments.@count > $0", 1 - // Find projects whose `comments` dictionary property contains only values of type 'string'. + // Find projects whose `comments` dictionary property contains + // only values of type 'string' "ALL comments.@type == 'string'" - // Find projects whose `comments` dictionary property contains no values of type 'int'. + // Find projects whose `comments` dictionary property contains + // no values of type 'int' "NONE comments.@type == 'int'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst index 569a31cb43..ecc72d500c 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.dot-notation.ts.rst @@ -1,4 +1,5 @@ .. code-block:: typescript - // Find projects whose `items` list property contains an item with a specific name. + // Find projects whose `items` list property contains an item + // with a specific name "items[0].name == 'Approve project plan'" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst index 6eb90698e5..f38eb068a9 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.equivalent-lists-any-operator.ts.rst @@ -2,4 +2,4 @@ "assignee == ANY { $0, $1 }", "Alex", "Ali" - "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied.) + "assignee == { $0, $1 }", "Alex", "Ali" // Equivalent (ANY is implied) diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst index 1a30b8df8d..f484e1de24 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-collection.ts.rst @@ -1,4 +1,5 @@ .. code-block:: typescript - // Find an item with the specified ObjectId value in the `items` collection. + // Find an item with the specified ObjectId value + // in the`items` collection "oid(631a072f75120729dc9223d9) IN items._id" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst index f51335bf6e..5dc01354ae 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-parameterized.ts.rst @@ -5,5 +5,6 @@ new BSON.ObjectId("631a0737c98f89f5b81cd24d"), new BSON.ObjectId("631a073c833a34ade21db2b2"), ]; - // Find items with an ObjectId value matching any value in the parameterized list. + // Find items with an ObjectId value matching any value + // in the parameterized list const parameterizedQuery = realm.objects(Item).filtered("_id IN $0", ids); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst index 94f7565ae0..95e23c3fc5 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.list-comparisons-static.ts.rst @@ -1,4 +1,5 @@ .. code-block:: typescript - // Find items with a priority value matching any value in the static list. + // Find items with a priority value matching any value + // in the static list "priority IN {0, 1, 2}" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst index f6a05abb5f..817b4fc9ea 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.logical-operators.ts.rst @@ -1,7 +1,7 @@ .. code-block:: typescript - // Find all items assigned to Ali AND marked completed. + // Find all items assigned to Ali AND marked completed "assignee == $0 AND isComplete == $1", "Ali", true - // Find all items assigned to Alex OR to Ali. + // Find all items assigned to Alex OR to Ali "assignee == $0 OR assignee == $1", "Alex", "Ali" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst index 6b39c15029..8c9df22d24 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.nil-type.ts.rst @@ -1,4 +1,4 @@ .. code-block:: typescript "assignee == nil" - "assignee == $0", null // 'null' maps to the SDK language's null pointer + "assignee == $0", null // 'null' maps to SDK language's null pointer diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst index e7cc775293..d8865fd19d 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.oid.ts.rst @@ -1,13 +1,17 @@ .. code-block:: typescript - // Find an item whose `_id` matches the ObjectID value passed to 'oid()'. + // Find an item whose `_id` matches the ObjectID value + // passed to 'oid()' "_id == oid(6001c033600510df3bbfd864)" - // Find an item whose `_id` matches the ObjectID passed as a parameterized query argument. + // Find an item whose `_id` matches the ObjectID passed as + // a parameterized query argument "_id == $0", oidValue - // Find an item whose `id` matches the UUID value passed to 'uuid()'. + // Find an item whose `id` matches the UUID value + // passed to 'uuid()' "id == uuid(d1b186e1-e9e0-4768-a1a7-c492519d47ee)" - // Find an item whose `_id` matches the UUID passed as a parameterized query argument. + // Find an item whose `_id` matches the UUID passed as + // a parameterized query argument "id == $0", uuidValue diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst index c37c93351e..69598f1ef6 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.parameterized-query.ts.rst @@ -1,7 +1,8 @@ .. code-block:: typescript - // Include one parameter with `$0`. + // Include one parameter with `$0` "progressMinutes > 1 AND assignee == $0", "Ali" - // Include multiple parameters using ascending integers, starting at`$0`. + // Include multiple parameters using ascending integers, + // starting at`$0` "progressMinutes > $0 AND assignee == $1", 1, "Alex" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst index 2f83d4846f..49e38c91c0 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.predicate.ts.rst @@ -1,6 +1,6 @@ .. code-block:: typescript - const expression = "priority == 1"; + "priority == 1" // Property Name: priority // Operator: == // Value: 1 diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst index ac69dc328e..7efe0eeca7 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.rql-fts.ts.rst @@ -4,9 +4,9 @@ "name TEXT $0", "write" // Use '-' to exclude: - // Find items with 'write' but not 'tests' in the name. + // Find items with 'write' but not 'tests' in the name "name TEXT $0", "write -tests" // Use '*' to match any characters after a prefix: - // Find items with a name that starts with 'wri'. + // Find items with a name that starts with 'wri' "name TEXT $0", "wri*" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst index 84cac7abce..f9fddbb007 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.set-operators.ts.rst @@ -1,16 +1,17 @@ .. code-block:: typescript - // Find projects with no complete items. + // Find projects with no complete items "NONE items.isComplete == $0", true - // Find projects that contain any item with priority 10. - "items.priority == $0", 10 // (ANY operator is implied.) + // Find projects that contain any item with priority 10 + "items.priority == $0", 10 // (ANY operator is implied) - // Find projects that only contain completed items. + // Find projects that only contain completed items "ALL items.isComplete == $0", true - // Find projects with at least one item assigned to either Alex or Ali. + // Find projects with at least one item assigned to + // either Alex or Ali "ANY items.assignee IN { $0 , $1 }", "Alex", "Ali" - // Find projects with no items assigned to either Alex or Ali. + // Find projects with no items assigned to either Alex or Ali "NONE items.assignee IN { $0 , $1 }", "Alex", "Ali" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst index 2dcfe9e8fd..9b77d1e44a 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.simple-query.ts.rst @@ -1,5 +1,5 @@ .. code-block:: typescript const items = realm.objects(Item); - // Get all items where 'priority' property is 7 or more. + // Get all items where 'priority' property is 7 or more const importantItems = items.filtered("priority >= $0", 7); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst index 298188b200..68917c33fb 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit-order-matters.ts.rst @@ -1,11 +1,11 @@ .. code-block:: typescript - // 1. Sorts by highest priority. - // 2. Returns the first item. - // 3. Remove duplicate names (N/A because a single item is always considered distinct). + // 1. Sorts by highest priority + // 2. Returns the first item + // 3. Remove duplicate names (N/A - a single item is always distinct) "assignee == null SORT(priority ASC) LIMIT(1) DISTINCT(name)" - // 1. Removes any duplicates by name. - // 2. Sorts by highest priority. - // 3. Returns the first item. + // 1. Removes any duplicates by name + // 2. Sorts by highest priority + // 3. Returns the first item "assignee == null DISTINCT(name) SORT(priority ASC) LIMIT(1)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst index 3268f78dec..5860a87bf8 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.sort-distinct-limit.ts.rst @@ -1,12 +1,13 @@ .. code-block:: typescript - // Find incomplete items, sort by `priority` in descending order, then - // sort equal `priority` values by `progressMinutes` in ascending order. + // Find incomplete items, sort by `priority` in descending order, + // then sort equal `priority` values by `progressMinutes` + // in ascending order "isComplete == false SORT(priority DESC, progressMinutes ASC)" // Find high priority items, then remove from the results any items - // with duplicate values for both `name` AND `assignee` properties. + // with duplicate values for both `name` AND `assignee` properties "priority >= 5 DISTINCT(name, assignee)" - // Find in-progress items, then return the first 10 results. + // Find in-progress items, then return the first 10 results "progressMinutes > 0 && isComplete != true LIMIT(10)" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst index 7fd3874072..3731055a67 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.string-operators.ts.rst @@ -1,13 +1,17 @@ .. code-block:: typescript - // Find projects whose name starts with 'E' or 'e' (case-insensitive). + // Find projects whose name starts with 'E' or 'e' + // (case-insensitive query) "name BEGINSWITH[c] $0", "E" - // Find projects whose name contains 'ie' (case-sensitive). + // Find projects whose name contains 'ie' + // (case-sensitive query) "name CONTAINS $0", "ie" - // Find items where the assignee name is lexicographically between 'Ali' and 'Chris' (case-sensitive). + // Find items where the assignee name is lexicographically between + // 'Ali' and 'Chris'(case-sensitive) "assignee BETWEEN { $0 , $1 }", "Ali", "Chris" - // Find projects where the street address is lexicographically greater than '123 Main St' (case-sensitive). + // Find projects where the street address is lexicographically + // greater than '123 Main St'(case-sensitive) "projectLocation.address.street > $0", "123 Main St" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst index 8b4e249ed2..53e6b7e2ac 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.subquery.ts.rst @@ -1,7 +1,8 @@ .. code-block:: typescript - // Find projects with incomplete items with 'Demo' in the name. + // Find projects with incomplete items with 'Demo' in the name "SUBQUERY(items, $item, $item.isComplete == false AND $item.name CONTAINS[c] 'Demo').@count > 0" - // Find projects where the number of completed items is greater than or equal to the project's `quota` property. + // Find projects where the number of completed items is + // greater than or equal to the project's `quota` property "SUBQUERY(items, $item, $item.isComplete == true).@count >= quota" diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst index c59fce1484..f321ed7245 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst @@ -1,11 +1,12 @@ .. code-block:: typescript - // Find projects with an `additionalInfo` property of string type. + // Find projects with an `additionalInfo` property of string type "additionalInfo.@type == 'string'" // Find projects with an `additionalInfo` property of - // `collection` type, which matches list or dictionary types. + // `collection` type, which matches list or dictionary types "additionalInfo.@type == 'collection'" - // Find projects with an `additionalInfo` property of list type, where any list element is of type 'bool'. + // Find projects with an `additionalInfo` property of list type, + // where any list element is of type 'bool' "additionalInfo[*].@type == 'bool'" From b28e7ace94bb8db997f528084d31e89e92706a50 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Fri, 19 Jul 2024 13:17:16 -0400 Subject: [PATCH 12/12] Apply final feedback --- .../__tests__/realm-query-language.test.js | 3 +- .../__tests__/realm-query-language.test.ts | 10 +- ...ge.test.snippet.aggregate-operators.ts.rst | 10 +- .../query-engines/realm-query-language.txt | 103 +++++++++--------- 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/examples/node/v12/__tests__/realm-query-language.test.js b/examples/node/v12/__tests__/realm-query-language.test.js index eadebe8baa..a265de2685 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.js +++ b/examples/node/v12/__tests__/realm-query-language.test.js @@ -423,7 +423,8 @@ describe("Realm Query Language Reference", () => { const longRunningProjects = projects.filtered( // [remove-end] - // Find projects with item `progressMinutes` greater than 100. + // Find projects where the sum total value of `progressMinutes` + // across all items is greater than 100. "items.@sum.progressMinutes > $0", 100 // [snippet-end] ); diff --git a/examples/node/v12/__tests__/realm-query-language.test.ts b/examples/node/v12/__tests__/realm-query-language.test.ts index 260e6afc02..fb16a7e8cc 100644 --- a/examples/node/v12/__tests__/realm-query-language.test.ts +++ b/examples/node/v12/__tests__/realm-query-language.test.ts @@ -405,7 +405,7 @@ describe("Realm Query Language Reference", () => { const allItemsLowerPriority = projects.filtered( // :remove-end: - // Find projects where maximum `priority` of all items is 5 + // Find projects where every item has a `priority` less than 5 "items.@max.priority < $0", priorityNum // :remove-start: @@ -414,7 +414,7 @@ describe("Realm Query Language Reference", () => { const allItemsHighPriority = projects.filtered( // :remove-end: - // Find projects where minimum `priority` of all items is 5 + // Find projects where every item has `priority` greater than 5 "items.@min.priority > $0", priorityNum // :remove-start: @@ -432,8 +432,10 @@ describe("Realm Query Language Reference", () => { const longRunningProjects = projects.filtered( // :remove-end: - // Find projects with item `progressMinutes` greater than 100 - "items.@sum.progressMinutes > $0", 100 + // Find projects where the sum total value of `progressMinutes` + // across all items is greater than 100 + "items.@sum.progressMinutes > $0", + 100 // :snippet-end: ); expect(longRunningProjects.length).toBe(1); diff --git a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst index 2562a827f3..9aff639ec7 100644 --- a/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst +++ b/source/examples/generated/node/v12/formatted/realm-query-language.test.snippet.aggregate-operators.ts.rst @@ -5,14 +5,16 @@ // Find projects with average item `priority` above 5 "items.@avg.priority > $0", priorityNum - // Find projects where maximum `priority` of all items is 5 + // Find projects where every item has a `priority` less than 5 "items.@max.priority < $0", priorityNum - // Find projects where minimum `priority` of all items is 5 + // Find projects where every item has `priority` greater than 5 "items.@min.priority > $0", priorityNum // Find projects with more than 5 items "items.@count > $0", 5 - // Find projects with item `progressMinutes` greater than 100 - "items.@sum.progressMinutes > $0", 100 + // Find projects where the sum total value of `progressMinutes` + // across all items is greater than 100 + "items.@sum.progressMinutes > $0", + 100 diff --git a/source/sdk/crud/query-engines/realm-query-language.txt b/source/sdk/crud/query-engines/realm-query-language.txt index 563d6bd8fe..fded46e8a1 100644 --- a/source/sdk/crud/query-engines/realm-query-language.txt +++ b/source/sdk/crud/query-engines/realm-query-language.txt @@ -128,7 +128,7 @@ parameterized for the specific data types: * - :ref:`Nil ` - "assignee == $0", null - "assignee == nil" - - For parameterized queries, ``nill`` maps to each SDK's respective null + - For parameterized queries, ``null`` maps to each SDK's respective null pointer. * - Boolean @@ -621,59 +621,10 @@ criteria: .. include:: examples/generated/node/v12/formatted/realm-query-language.test.snippet.type-operator.ts.rst + Type-Specific Queries --------------------- -.. _rql-backlinks: - -Backlink Queries -~~~~~~~~~~~~~~~~ - -A **backlink** is an :ref:`inverse relationship ` link that -lets you query objects that reference another object. Backlinks use the to-one -and to-many relationships defined in your object schemas but reverse the -direction. Every relationship that you define in your schema implicitly has a -corresponding backlink. - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Operator - - Description - - * - ``@links`` - - Accesses the backlink of a relationship specified by the object type and - property name (``@links..``). - * - ``@count`` - - The number of elements in a backlink collection. You can use the - ``@count`` operator directly on ``@links`` to query the count of all - relationships that point to an object. - -You can access backlinks: - -- Using the ``@links..`` syntax, where - ```` and ```` refer to a specific property on an - object type that references the queried object type. - - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst - -- Using the ``linkingObjects`` property to explicitly include the backlink in - your data model. This lets you reference the backlink through an assigned - property name using :ref:`dot notation `. - - .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst - -The result of a backlink is treated like a collection and supports -:ref:`collection operators ` and -:ref:`aggregate operators `. - -The following examples find items based on the projects they belong to through -the ``@links`` operator or the ``projects`` property: - -.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst - - .. _rql-date-operators: Date Queries @@ -802,6 +753,56 @@ property against the boundaries of the ``GeoCircle`` shape named geospatial data. +.. _rql-backlinks: + +Inverse Relationship Queries (Backlinks) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can query an object's :ref:`inverse relationship ` to +another object through its **backlink**. Backlinks use the to-one +and to-many relationships defined in your object schemas but reverse the +direction. Every relationship that you define in your schema implicitly has a +corresponding backlink. + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Operator + - Description + + * - ``@links`` + - Accesses the inverse relationship specified by the object type and + property name (``@links..``). + * - ``@count`` + - The number of elements in a backlink collection. You can use the + ``@count`` operator directly on ``@links`` to query the count of all + relationships that point to an object. + +You can access an inverse relationship: + +- Using the ``@links..`` syntax, where + ```` and ```` refer to a specific property on an + object type that references the queried object type. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-atLinks.ts.rst + +- Using the ``linkingObjects`` property to explicitly include the backlink in + your data model. This lets you reference the backlink through an assigned + property name using :ref:`dot notation `. + + .. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-linkingObjects.ts.rst + +The result is treated like a collection and supports :ref:`collection operators +` and :ref:`aggregate operators +`. + +The following examples find items based on the projects they belong to through +the ``@links`` operator or the ``projects`` property: + +.. include:: /examples/generated/node/v12/formatted/realm-query-language.test.snippet.backlinks-collection-operators.ts.rst + + .. _rql-list-queries: List Comparison Queries