@dotcms/client 0.0.1-alpha.37 → 0.0.1-alpha.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.eslintrc.json +18 -0
  2. package/README.md +4 -4
  3. package/jest.config.ts +15 -0
  4. package/package.json +3 -15
  5. package/project.json +72 -0
  6. package/src/index.ts +30 -0
  7. package/src/lib/client/content/builders/collection/collection.spec.ts +515 -0
  8. package/src/lib/client/content/builders/collection/collection.ts +416 -0
  9. package/src/lib/client/content/content-api.ts +139 -0
  10. package/src/lib/client/content/shared/const.ts +15 -0
  11. package/src/lib/client/content/shared/types.ts +155 -0
  12. package/src/lib/client/content/shared/utils.ts +28 -0
  13. package/src/lib/client/models/index.ts +19 -0
  14. package/src/lib/client/models/types.ts +14 -0
  15. package/src/lib/client/sdk-js-client.spec.ts +483 -0
  16. package/src/lib/client/sdk-js-client.ts +442 -0
  17. package/src/lib/editor/listeners/listeners.spec.ts +119 -0
  18. package/src/lib/editor/listeners/listeners.ts +223 -0
  19. package/src/lib/editor/models/{client.model.d.ts → client.model.ts} +19 -16
  20. package/src/lib/editor/models/{editor.model.d.ts → editor.model.ts} +9 -5
  21. package/src/lib/editor/models/{listeners.model.d.ts → listeners.model.ts} +9 -6
  22. package/src/lib/editor/sdk-editor-vtl.ts +31 -0
  23. package/src/lib/editor/sdk-editor.spec.ts +116 -0
  24. package/src/lib/editor/sdk-editor.ts +105 -0
  25. package/src/lib/editor/utils/editor.utils.spec.ts +206 -0
  26. package/src/lib/editor/utils/editor.utils.ts +258 -0
  27. package/src/lib/query-builder/lucene-syntax/{Equals.d.ts → Equals.ts} +83 -18
  28. package/src/lib/query-builder/lucene-syntax/Field.ts +40 -0
  29. package/src/lib/query-builder/lucene-syntax/{NotOperand.d.ts → NotOperand.ts} +18 -6
  30. package/src/lib/query-builder/lucene-syntax/{Operand.d.ts → Operand.ts} +21 -7
  31. package/src/lib/query-builder/sdk-query-builder.spec.ts +159 -0
  32. package/src/lib/query-builder/sdk-query-builder.ts +87 -0
  33. package/src/lib/query-builder/utils/index.ts +179 -0
  34. package/src/lib/utils/graphql/transforms.spec.ts +150 -0
  35. package/src/lib/utils/graphql/transforms.ts +99 -0
  36. package/src/lib/utils/page/common-utils.spec.ts +37 -0
  37. package/src/lib/utils/page/common-utils.ts +64 -0
  38. package/tsconfig.json +22 -0
  39. package/tsconfig.lib.json +13 -0
  40. package/tsconfig.spec.json +9 -0
  41. package/index.cjs.d.ts +0 -1
  42. package/index.cjs.default.js +0 -1
  43. package/index.cjs.js +0 -1490
  44. package/index.cjs.mjs +0 -2
  45. package/index.esm.d.ts +0 -1
  46. package/index.esm.js +0 -1481
  47. package/src/index.d.ts +0 -6
  48. package/src/lib/client/content/builders/collection/collection.d.ts +0 -148
  49. package/src/lib/client/content/content-api.d.ts +0 -78
  50. package/src/lib/client/content/shared/const.d.ts +0 -3
  51. package/src/lib/client/content/shared/types.d.ts +0 -62
  52. package/src/lib/client/content/shared/utils.d.ts +0 -12
  53. package/src/lib/client/models/index.d.ts +0 -1
  54. package/src/lib/client/models/types.d.ts +0 -5
  55. package/src/lib/client/sdk-js-client.d.ts +0 -193
  56. package/src/lib/editor/listeners/listeners.d.ts +0 -46
  57. package/src/lib/editor/sdk-editor-vtl.d.ts +0 -6
  58. package/src/lib/editor/sdk-editor.d.ts +0 -29
  59. package/src/lib/editor/utils/editor.utils.d.ts +0 -83
  60. package/src/lib/query-builder/lucene-syntax/Field.d.ts +0 -23
  61. package/src/lib/query-builder/sdk-query-builder.d.ts +0 -42
  62. package/src/lib/query-builder/utils/index.d.ts +0 -91
  63. package/src/lib/utils/graphql/transforms.d.ts +0 -11
  64. package/src/lib/utils/page/common-utils.d.ts +0 -11
  65. /package/src/lib/query-builder/lucene-syntax/{index.d.ts → index.ts} +0 -0
  66. /package/src/lib/utils/{index.d.ts → index.ts} +0 -0
@@ -0,0 +1,206 @@
1
+ import { getContentletsBound, scrollIsInBottom } from './editor.utils';
2
+
3
+ describe('getContentletsBound', () => {
4
+ const createContentlet = ({
5
+ x,
6
+ y,
7
+ width,
8
+ height,
9
+ dataset
10
+ }: {
11
+ x: number;
12
+ y: number;
13
+ width: number;
14
+ height: number;
15
+ dataset: { [key: string]: string };
16
+ }): HTMLDivElement => {
17
+ const contentlet = document.createElement('div');
18
+ const mockGetBoundingClientRect = jest.fn(() => ({
19
+ x,
20
+ y,
21
+ width,
22
+ height
23
+ })) as unknown as () => DOMRect;
24
+ contentlet.getBoundingClientRect = mockGetBoundingClientRect;
25
+ Object.keys(dataset).forEach((key) => {
26
+ contentlet.setAttribute(`data-${key}`, dataset[key]);
27
+ });
28
+
29
+ return contentlet;
30
+ };
31
+
32
+ const containerRect = {
33
+ x: 0,
34
+ y: 0,
35
+ width: 100,
36
+ height: 100,
37
+ top: 0,
38
+ right: 100,
39
+ bottom: 100,
40
+ left: 0
41
+ } as DOMRect;
42
+
43
+ const contentlets: HTMLDivElement[] = [
44
+ createContentlet({
45
+ x: 10,
46
+ y: 20,
47
+ width: 30,
48
+ height: 40,
49
+ dataset: {
50
+ 'dot-container': JSON.stringify({ uuid: 'container1' }),
51
+ 'dot-identifier': 'contentlet1',
52
+ 'dot-title': 'Contentlet 1',
53
+ 'dot-inode': 'inode1',
54
+ 'dot-type': 'type1'
55
+ }
56
+ }),
57
+ createContentlet({
58
+ x: 50,
59
+ y: 60,
60
+ width: 70,
61
+ height: 80,
62
+ dataset: {
63
+ 'dot-container': JSON.stringify({ uuid: 'container1' }),
64
+ 'dot-identifier': 'contentlet2',
65
+ 'dot-title': 'Contentlet 2',
66
+ 'dot-inode': 'inode2',
67
+ 'dot-type': 'type2'
68
+ }
69
+ })
70
+ ];
71
+
72
+ it('should return an array of contentlets bound from contentlet with data atrribute dotContainer ', () => {
73
+ const result = getContentletsBound(containerRect, contentlets);
74
+
75
+ expect(result).toEqual([
76
+ {
77
+ x: 0,
78
+ y: 20,
79
+ width: 30,
80
+ height: 40,
81
+ payload: JSON.stringify({
82
+ container: { uuid: 'container1' },
83
+ contentlet: {
84
+ identifier: 'contentlet1',
85
+ title: 'Contentlet 1',
86
+ inode: 'inode1',
87
+ contentType: 'type1'
88
+ }
89
+ })
90
+ },
91
+ {
92
+ x: 0,
93
+ y: 60,
94
+ width: 70,
95
+ height: 80,
96
+ payload: JSON.stringify({
97
+ container: { uuid: 'container1' },
98
+ contentlet: {
99
+ identifier: 'contentlet2',
100
+ title: 'Contentlet 2',
101
+ inode: 'inode2',
102
+ contentType: 'type2'
103
+ }
104
+ })
105
+ }
106
+ ]);
107
+ });
108
+
109
+ it('should return an empty array if contentlets is empty', () => {
110
+ const result = getContentletsBound(containerRect, []);
111
+
112
+ expect(result).toEqual([]);
113
+ });
114
+
115
+ it('should return an array of contentlets with correct properties when dotContainer is not present in dataset', () => {
116
+ const contentletsWithMissingContainer: HTMLDivElement[] = [
117
+ createContentlet({
118
+ x: 10,
119
+ y: 20,
120
+ width: 30,
121
+ height: 40,
122
+ dataset: {
123
+ 'dot-identifier': 'contentlet1',
124
+ 'dot-title': 'Contentlet 1',
125
+ 'dot-inode': 'inode1',
126
+ 'dot-type': 'type1'
127
+ }
128
+ })
129
+ ];
130
+
131
+ const container = document.createElement('div');
132
+
133
+ container.appendChild(contentletsWithMissingContainer[0]);
134
+ container.setAttribute('data-dot-object', 'container');
135
+ container.setAttribute('data-dot-accept-types', '[Blogs]');
136
+ container.setAttribute('data-dot-identifier', '1');
137
+ container.setAttribute('data-max-contentlets', '1');
138
+ container.setAttribute('data-dot-uuid', '1');
139
+ const result = getContentletsBound(containerRect, contentletsWithMissingContainer);
140
+
141
+ expect(result).toEqual([
142
+ {
143
+ x: 0,
144
+ y: 20,
145
+ width: 30,
146
+ height: 40,
147
+ payload: JSON.stringify({
148
+ container: {
149
+ acceptTypes: '[Blogs]',
150
+ identifier: '1',
151
+ maxContentlets: '1',
152
+ uuid: '1'
153
+ },
154
+ contentlet: {
155
+ identifier: 'contentlet1',
156
+ title: 'Contentlet 1',
157
+ inode: 'inode1',
158
+ contentType: 'type1'
159
+ }
160
+ })
161
+ }
162
+ ]);
163
+ });
164
+ });
165
+
166
+ describe('scrollIsInBottom', () => {
167
+ it('should return true when scroll position + viewport height equals document height', () => {
168
+ Object.defineProperty(window, 'innerHeight', {
169
+ writable: true,
170
+ configurable: true,
171
+ value: 500
172
+ });
173
+ Object.defineProperty(window, 'scrollY', {
174
+ writable: true,
175
+ configurable: true,
176
+ value: 500
177
+ });
178
+ Object.defineProperty(document.documentElement, 'scrollHeight', {
179
+ writable: true,
180
+ configurable: true,
181
+ value: 1000
182
+ });
183
+
184
+ expect(scrollIsInBottom()).toBe(true);
185
+ });
186
+
187
+ it('should return false when scroll position + viewport height is less than document height', () => {
188
+ Object.defineProperty(window, 'innerHeight', {
189
+ writable: true,
190
+ configurable: true,
191
+ value: 500
192
+ });
193
+ Object.defineProperty(window, 'scrollY', {
194
+ writable: true,
195
+ configurable: true,
196
+ value: 400
197
+ });
198
+ Object.defineProperty(document.documentElement, 'scrollHeight', {
199
+ writable: true,
200
+ configurable: true,
201
+ value: 1000
202
+ });
203
+
204
+ expect(scrollIsInBottom()).toBe(false);
205
+ });
206
+ });
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Bound information for a contentlet.
3
+ *
4
+ * @interface ContentletBound
5
+ * @property {number} x - The x-coordinate of the contentlet.
6
+ * @property {number} y - The y-coordinate of the contentlet.
7
+ * @property {number} width - The width of the contentlet.
8
+ * @property {number} height - The height of the contentlet.
9
+ * @property {string} payload - The payload data of the contentlet in JSON format.
10
+ */
11
+ interface ContentletBound {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ payload: string;
17
+ }
18
+
19
+ /**
20
+ * Bound information for a container.
21
+ *
22
+ * @interface ContainerBound
23
+ * @property {number} x - The x-coordinate of the container.
24
+ * @property {number} y - The y-coordinate of the container.
25
+ * @property {number} width - The width of the container.
26
+ * @property {number} height - The height of the container.
27
+ * @property {string} payload - The payload data of the container in JSON format.
28
+ * @property {ContentletBound[]} contentlets - An array of contentlets within the container.
29
+ */
30
+ interface ContainerBound {
31
+ x: number;
32
+ y: number;
33
+ width: number;
34
+ height: number;
35
+ payload: string;
36
+ contentlets: ContentletBound[];
37
+ }
38
+
39
+ /**
40
+ * Calculates the bounding information for each page element within the given containers.
41
+ *
42
+ * @export
43
+ * @param {HTMLDivElement[]} containers - An array of HTMLDivElement representing the containers.
44
+ * @return {ContainerBound[]} An array of objects containing the bounding information for each page element.
45
+ * @example
46
+ * ```ts
47
+ * const containers = document.querySelectorAll('.container');
48
+ * const bounds = getPageElementBound(containers);
49
+ * console.log(bounds);
50
+ * ```
51
+ */
52
+ export function getPageElementBound(containers: HTMLDivElement[]): ContainerBound[] {
53
+ return containers.map((container) => {
54
+ const containerRect = container.getBoundingClientRect();
55
+ const contentlets = Array.from(
56
+ container.querySelectorAll('[data-dot-object="contentlet"]')
57
+ ) as HTMLDivElement[];
58
+
59
+ return {
60
+ x: containerRect.x,
61
+ y: containerRect.y,
62
+ width: containerRect.width,
63
+ height: containerRect.height,
64
+ payload: JSON.stringify({
65
+ container: getContainerData(container)
66
+ }),
67
+ contentlets: getContentletsBound(containerRect, contentlets)
68
+ };
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Calculates the bounding information for each contentlet inside a container.
74
+ *
75
+ * @export
76
+ * @param {DOMRect} containerRect - The bounding rectangle of the container.
77
+ * @param {HTMLDivElement[]} contentlets - An array of HTMLDivElement representing the contentlets.
78
+ * @return {ContentletBound[]} An array of objects containing the bounding information for each contentlet.
79
+ * @example
80
+ * ```ts
81
+ * const containerRect = container.getBoundingClientRect();
82
+ * const contentlets = container.querySelectorAll('.contentlet');
83
+ * const bounds = getContentletsBound(containerRect, contentlets);
84
+ * console.log(bounds); // Element bounds within the container
85
+ * ```
86
+ */
87
+ export function getContentletsBound(
88
+ containerRect: DOMRect,
89
+ contentlets: HTMLDivElement[]
90
+ ): ContentletBound[] {
91
+ return contentlets.map((contentlet) => {
92
+ const contentletRect = contentlet.getBoundingClientRect();
93
+
94
+ return {
95
+ x: 0,
96
+ y: contentletRect.y - containerRect.y,
97
+ width: contentletRect.width,
98
+ height: contentletRect.height,
99
+ payload: JSON.stringify({
100
+ container: contentlet.dataset?.['dotContainer']
101
+ ? JSON.parse(contentlet.dataset?.['dotContainer'])
102
+ : getClosestContainerData(contentlet),
103
+ contentlet: {
104
+ identifier: contentlet.dataset?.['dotIdentifier'],
105
+ title: contentlet.dataset?.['dotTitle'],
106
+ inode: contentlet.dataset?.['dotInode'],
107
+ contentType: contentlet.dataset?.['dotType']
108
+ }
109
+ })
110
+ };
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Get container data from VTLS.
116
+ *
117
+ * @export
118
+ * @param {HTMLElement} container - The container element.
119
+ * @return {object} An object containing the container data.
120
+ * @example
121
+ * ```ts
122
+ * const container = document.querySelector('.container');
123
+ * const data = getContainerData(container);
124
+ * console.log(data);
125
+ * ```
126
+ */
127
+ export function getContainerData(container: HTMLElement) {
128
+ return {
129
+ acceptTypes: container.dataset?.['dotAcceptTypes'] || '',
130
+ identifier: container.dataset?.['dotIdentifier'] || '',
131
+ maxContentlets: container.dataset?.['maxContentlets'] || '',
132
+ uuid: container.dataset?.['dotUuid'] || ''
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Get the closest container data from the contentlet.
138
+ *
139
+ * @export
140
+ * @param {Element} element - The contentlet element.
141
+ * @return {object | null} An object containing the closest container data or null if no container is found.
142
+ * @example
143
+ * ```ts
144
+ * const contentlet = document.querySelector('.contentlet');
145
+ * const data = getClosestContainerData(contentlet);
146
+ * console.log(data);
147
+ * ```
148
+ */
149
+ export function getClosestContainerData(element: Element) {
150
+ // Find the closest ancestor element with data-dot-object="container" attribute
151
+ const container = element.closest('[data-dot-object="container"]') as HTMLElement;
152
+
153
+ // If a container element is found
154
+ if (container) {
155
+ // Return the dataset of the container element
156
+ return getContainerData(container);
157
+ } else {
158
+ // If no container element is found, return null
159
+ console.warn('No container found for the contentlet');
160
+
161
+ return null;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Find the closest contentlet element based on HTMLElement.
167
+ *
168
+ * @export
169
+ * @param {HTMLElement | null} element - The starting element.
170
+ * @return {HTMLElement | null} The closest contentlet element or null if not found.
171
+ * @example
172
+ * const element = document.querySelector('.some-element');
173
+ * const contentlet = findDotElement(element);
174
+ * console.log(contentlet);
175
+ */
176
+ export function findDotElement(element: HTMLElement | null): HTMLElement | null {
177
+ if (!element) return null;
178
+
179
+ if (
180
+ element?.dataset?.['dotObject'] === 'contentlet' ||
181
+ (element?.dataset?.['dotObject'] === 'container' && element.children.length === 0)
182
+ ) {
183
+ return element;
184
+ }
185
+
186
+ return findDotElement(element?.['parentElement']);
187
+ }
188
+
189
+ /**
190
+ * Find the closest VTL file element based on HTMLElement.
191
+ *
192
+ * @export
193
+ * @param {HTMLElement | null} element - The starting element.
194
+ * @return {HTMLElement | null} The closest VTL file element or null if not found.
195
+ * @example
196
+ * const element = document.querySelector('.some-element');
197
+ * const vtlFile = findDotVTLElement(element);
198
+ * console.log(vtlFile);
199
+ */
200
+ export function findDotVTLElement(element: HTMLElement | null): HTMLElement | null {
201
+ if (!element) return null;
202
+
203
+ if (element.dataset && element.dataset?.['dotObject'] === 'vtl-file') {
204
+ return element;
205
+ } else {
206
+ return findDotElement(element?.['parentElement']);
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Find VTL data within a target element.
212
+ *
213
+ * @export
214
+ * @param {HTMLElement} target - The target element to search within.
215
+ * @return {Array<{ inode: string, name: string }> | null} An array of objects containing VTL data or null if none found.
216
+ * @example
217
+ * ```ts
218
+ * const target = document.querySelector('.target-element');
219
+ * const vtlData = findVTLData(target);
220
+ * console.log(vtlData);
221
+ * ```
222
+ */
223
+ export function findVTLData(target: HTMLElement) {
224
+ const vltElements = target.querySelectorAll(
225
+ '[data-dot-object="vtl-file"]'
226
+ ) as NodeListOf<HTMLElement>;
227
+
228
+ if (!vltElements.length) {
229
+ return null;
230
+ }
231
+
232
+ return Array.from(vltElements).map((vltElement) => {
233
+ return {
234
+ inode: vltElement.dataset?.['dotInode'],
235
+ name: vltElement.dataset?.['dotUrl']
236
+ };
237
+ });
238
+ }
239
+
240
+ /**
241
+ * Check if the scroll position is at the bottom of the page.
242
+ *
243
+ * @export
244
+ * @return {boolean} True if the scroll position is at the bottom, otherwise false.
245
+ * @example
246
+ * ```ts
247
+ * if (scrollIsInBottom()) {
248
+ * console.log('Scrolled to the bottom');
249
+ * }
250
+ * ```
251
+ */
252
+ export function scrollIsInBottom() {
253
+ const documentHeight = document.documentElement.scrollHeight;
254
+ const viewportHeight = window.innerHeight;
255
+ const scrollY = window.scrollY;
256
+
257
+ return scrollY + viewportHeight >= documentHeight;
258
+ }
@@ -1,6 +1,17 @@
1
1
  import { Field } from './Field';
2
2
  import { NotOperand } from './NotOperand';
3
3
  import { Operand } from './Operand';
4
+
5
+ import {
6
+ OPERAND,
7
+ buildExcludeField,
8
+ buildField,
9
+ buildNotOperand,
10
+ buildOperand,
11
+ buildRawEquals,
12
+ sanitizeQuery
13
+ } from '../utils';
14
+
4
15
  /**
5
16
  * 'Equal' Is a Typescript class that provides the ability to use terms in the lucene query string.
6
17
  * A term is a value used to search for a specific value in a document. It can be a word or a phrase.
@@ -10,74 +21,128 @@ import { Operand } from './Operand';
10
21
  * @export
11
22
  * @class Equal
12
23
  */
13
- export declare class Equals {
14
- #private;
15
- private query;
16
- constructor(query: string);
24
+ export class Equals {
25
+ #query = '';
26
+
27
+ constructor(private query: string) {
28
+ this.#query = this.query;
29
+ }
30
+
17
31
  /**
18
32
  * This method appends to the query a term that should be excluded in the search.
19
33
  *
20
- * Ex: "-myValue"
34
+ * @example
35
+ * ```ts
36
+ * const equals = new Equals("+myField: myValue");
37
+ * equals.excludeField("myField2").equals("myValue2"); // Current query: "+myField: myValue -myField2: myValue2"
38
+ * ```
21
39
  *
22
40
  * @param {string} field - The field that should be excluded in the search.
23
41
  * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
24
42
  * @memberof Equal
25
43
  */
26
- excludeField(field: string): Field;
44
+ excludeField(field: string): Field {
45
+ return buildExcludeField(this.#query, field);
46
+ }
47
+
27
48
  /**
28
49
  * This method appends to the query a field that should be included in the search.
29
50
  *
30
- * Ex: "+myField:"
31
- *
51
+ * @example
52
+ * ```ts
53
+ * const equals = new Equals("+myField: myValue");
54
+ * equals.field("myField2").equals("myValue2"); // Current query: "+myField: myValue +myField2: myValue2"
55
+ *```
32
56
  * @param {string} field - The field that should be included in the search.
33
57
  * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
34
58
  * @memberof Equal
35
59
  */
36
- field(field: string): Field;
60
+ field(field: string): Field {
61
+ return buildField(this.#query, field);
62
+ }
63
+
37
64
  /**
38
65
  * This method appends to the query an operand to use logic operators in the query.
39
66
  *
40
- * Ex: "OR"
67
+ * @example
68
+ * @example
69
+ * ```ts
70
+ * const equals = new Equals("+myField: myValue");
71
+ * equals.or().field("myField2").equals("myValue2"); // Current query: "+myField: myValue OR +myField2: myValue2"
72
+ * ```
41
73
  *
42
74
  * @return {*} {Operand} - An instance of a Lucene Operand. An operand is a logical operator used to combine terms or phrases in a query.
43
75
  * @memberof Equal
44
76
  */
45
- or(): Operand;
77
+ or(): Operand {
78
+ return buildOperand(this.#query, OPERAND.OR);
79
+ }
80
+
46
81
  /**
47
82
  * This method appends to the query an operand to use logic operators in the query.
48
83
  *
49
- * Ex: "AND"
84
+ * @example
85
+ * ```ts
86
+ * const equals = new Equals("+myField: myValue");
87
+ * equals.and().field("myField2").equals("myValue2"); // Current query: "+myField: myValue AND +myField2: myValue2"
88
+ * ```
50
89
  *
51
90
  * @return {*} {Operand} - An instance of a Lucene Operand. An operand is a logical operator used to combine terms or phrases in a query.
52
91
  * @memberof Equal
53
92
  */
54
- and(): Operand;
93
+ and(): Operand {
94
+ return buildOperand(this.#query, OPERAND.AND);
95
+ }
96
+
55
97
  /**
56
98
  * This method appends to the query an operand to use logic operators in the query.
57
99
  *
58
- * Ex: "NOT"
100
+ * @example
101
+ * ```ts
102
+ * const equals = new Equals("+myField: myValue");
103
+ * equals.not().field("myField").equals("myValue2"); // Current query: "+myField: myValue NOT +myField: myValue2"
104
+ * ```
59
105
  *
60
106
  * @return {*} {NotOperand} - An instance of a Lucene Not Operand. A not operand is a logical operator used to exclude terms or phrases in a query.
61
107
  * @memberof Equal
62
108
  */
63
- not(): NotOperand;
109
+ not(): NotOperand {
110
+ return buildNotOperand(this.#query);
111
+ }
112
+
64
113
  /**
65
114
  * This method allows to pass a raw query string to the query builder.
66
115
  * This raw query should end in a Lucene Equal.
67
116
  * This method is useful when you want to append a complex query or an already written query to the query builder.
68
117
  *
69
- * Ex: "+myField: value AND (someOtherValue OR anotherValue)"
118
+ * @example
119
+ * ```ts
120
+ * // This builds the follow raw query "+myField: value AND (someOtherValue OR anotherValue)"
121
+ * const equals = new Equals("+myField: value");
122
+ * equals.raw("+myField2: value2"); // Current query: "+myField: value +myField2: anotherValue"
123
+ * ```
70
124
  *
71
125
  * @param {string} query - A raw query string.
72
126
  * @return {*} {Equal} - An instance of a Lucene Equal. A term is a value used to search for a specific value in a document.
73
127
  * @memberof QueryBuilder
74
128
  */
75
- raw(query: string): Equals;
129
+ raw(query: string): Equals {
130
+ return buildRawEquals(this.#query, query);
131
+ }
132
+
76
133
  /**
77
134
  * This method returns the final query string.
78
135
  *
136
+ * @example
137
+ * ```ts
138
+ * const equals = new Equals("+myField: myValue");
139
+ * equals.field("myField2").equals("myValue2").build(); // Returns "+myField: myValue +myField2: myValue2"
140
+ * ```
141
+ *
79
142
  * @return {*} {string} - The final query string.
80
143
  * @memberof Equal
81
144
  */
82
- build(): string;
145
+ build(): string {
146
+ return sanitizeQuery(this.#query);
147
+ }
83
148
  }
@@ -0,0 +1,40 @@
1
+ import { Equals } from './Equals';
2
+
3
+ import { buildEquals } from '../utils';
4
+
5
+ /**
6
+ * The `Field` class is used to build a query with a specific field.
7
+ * A Lucene Field is a key used to search for a specific value in a document.
8
+ *
9
+ * @export
10
+ * @class Field
11
+ */
12
+ export class Field {
13
+ #query = '';
14
+
15
+ /**
16
+ * Creates an instance of the `Field` class.
17
+ *
18
+ * @param {string} query - The initial query string.
19
+ */
20
+ constructor(private query: string) {
21
+ this.#query = this.query;
22
+ }
23
+
24
+ /**
25
+ * Appends a term to the query that should be included in the search.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const field = new Field("+myField");
30
+ * field.equals("myValue");
31
+ * ```
32
+ *
33
+ * @param {string} term - The term that should be included in the search.
34
+ * @return {Equals} - An instance of `Equals`.
35
+ * @memberof Field
36
+ */
37
+ equals(term: string): Equals {
38
+ return buildEquals(this.#query, term);
39
+ }
40
+ }