Skip to content

Commit 751bf0b

Browse files
authored
Merge pull request #340 from cakephp/mappin_generator_mappings
Add support for complex mappings in MappingGenerator
2 parents 86c3598 + 0dd445a commit 751bf0b

2 files changed

Lines changed: 206 additions & 6 deletions

File tree

src/TestSuite/Fixture/MappingGenerator.php

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,38 @@
1313
* Index definition files should return an array of indexes
1414
* to create. Each index in the array should follow the form of
1515
*
16+
* Simple mapping (properties only):
1617
* ```
1718
* [
1819
* 'name' => 'articles',
19-
* 'mapping' => [...],
20+
* 'mapping' => [
21+
* 'title' => ['type' => 'text'],
22+
* 'body' => ['type' => 'text'],
23+
* ],
24+
* 'settings' => [...],
25+
* ]
26+
* ```
27+
*
28+
* Full mapping structure (with dynamic_templates, etc.):
29+
* ```
30+
* [
31+
* 'name' => 'articles',
32+
* 'mapping' => [
33+
* 'properties' => [
34+
* 'title' => ['type' => 'text'],
35+
* 'body' => ['type' => 'text'],
36+
* ],
37+
* 'dynamic_templates' => [...],
38+
* 'dynamic' => 'strict',
39+
* ],
2040
* 'settings' => [...],
2141
* ]
2242
* ```
2343
*
2444
* The `mapping` key should be compatible with Elasticsearch's
25-
* mapping API and Elastica.
45+
* mapping API and Elastica. If the mapping contains a 'properties'
46+
* key, it will be treated as a full mapping structure. Otherwise,
47+
* it will be wrapped in a 'properties' key for backward compatibility.
2648
*
2749
* The `settings` key can contain Elastica compatible index creation
2850
* settings.
@@ -103,6 +125,12 @@ protected function dropIndex(Connection $db, string $name): void
103125
/**
104126
* Create an index.
105127
*
128+
* Supports two mapping formats:
129+
* - Simple: Direct property definitions (wrapped in 'properties' automatically)
130+
* - Full: Complete mapping structure including 'properties', 'dynamic_templates', etc.
131+
*
132+
* The format is detected by checking if the mapping contains a 'properties' key.
133+
*
106134
* @param \Cake\ElasticSearch\Datasource\Connection $db The connection.
107135
* @param array $mapping The index mapping and settings.
108136
*/
@@ -119,11 +147,17 @@ protected function createIndex(Connection $db, array $mapping): void
119147
$args['settings'] = $mapping['settings'];
120148
}
121149

122-
// In Elastica, mappings should be included in index creation
150+
// Detect if this is a full mapping structure or simple properties
123151
if (!empty($mapping['mapping'])) {
124-
$args['mappings'] = [
125-
'properties' => $mapping['mapping'],
126-
];
152+
if (isset($mapping['mapping']['properties'])) {
153+
// Full mapping structure - use as-is to support dynamic_templates, etc.
154+
$args['mappings'] = $mapping['mapping'];
155+
} else {
156+
// Simple properties only - wrap for backward compatibility
157+
$args['mappings'] = [
158+
'properties' => $mapping['mapping'],
159+
];
160+
}
127161
}
128162

129163
$response = $esIndex->create($args);

tests/TestCase/TestSuite/Fixture/MappingGeneratorTest.php

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,172 @@ public function testReloadWithSettings(): void
332332
unlink($file);
333333
}
334334

335+
/**
336+
* Test simple mapping format (backward compatibility)
337+
*/
338+
public function testSimpleMappingFormat(): void
339+
{
340+
$file = $this->createMappingFile([
341+
[
342+
'name' => 'test_index_1',
343+
'mapping' => [
344+
'id' => ['type' => 'integer'],
345+
'title' => ['type' => 'text'],
346+
'body' => ['type' => 'text'],
347+
],
348+
],
349+
]);
350+
351+
$generator = new MappingGenerator($file, 'test');
352+
$generator->reload(['test_index_1']);
353+
354+
$index = $this->connection->getIndex('test_index_1');
355+
$this->assertTrue($index->exists());
356+
357+
// Verify mapping was created correctly
358+
$mapping = $index->getMapping();
359+
$this->assertNotEmpty($mapping);
360+
$this->assertArrayHasKey('properties', $mapping);
361+
362+
$properties = $mapping['properties'];
363+
$this->assertArrayHasKey('id', $properties);
364+
$this->assertArrayHasKey('title', $properties);
365+
$this->assertArrayHasKey('body', $properties);
366+
367+
unlink($file);
368+
}
369+
370+
/**
371+
* Test full mapping format with properties key
372+
*/
373+
public function testFullMappingFormatWithProperties(): void
374+
{
375+
$file = $this->createMappingFile([
376+
[
377+
'name' => 'test_index_1',
378+
'mapping' => [
379+
'properties' => [
380+
'id' => ['type' => 'integer'],
381+
'title' => ['type' => 'text'],
382+
'body' => ['type' => 'text'],
383+
],
384+
],
385+
],
386+
]);
387+
388+
$generator = new MappingGenerator($file, 'test');
389+
$generator->reload(['test_index_1']);
390+
391+
$index = $this->connection->getIndex('test_index_1');
392+
$this->assertTrue($index->exists());
393+
394+
// Verify mapping was created correctly
395+
$mapping = $index->getMapping();
396+
$this->assertNotEmpty($mapping);
397+
$this->assertArrayHasKey('properties', $mapping);
398+
399+
$properties = $mapping['properties'];
400+
$this->assertArrayHasKey('id', $properties);
401+
$this->assertArrayHasKey('title', $properties);
402+
$this->assertArrayHasKey('body', $properties);
403+
404+
unlink($file);
405+
}
406+
407+
/**
408+
* Test full mapping format with dynamic_templates
409+
*/
410+
public function testFullMappingFormatWithDynamicTemplates(): void
411+
{
412+
$file = $this->createMappingFile([
413+
[
414+
'name' => 'test_index_1',
415+
'mapping' => [
416+
'properties' => [
417+
'id' => ['type' => 'integer'],
418+
'title' => ['type' => 'text'],
419+
],
420+
'dynamic_templates' => [
421+
[
422+
'strings_as_keywords' => [
423+
'match_mapping_type' => 'string',
424+
'mapping' => [
425+
'type' => 'keyword',
426+
],
427+
],
428+
],
429+
],
430+
],
431+
],
432+
]);
433+
434+
$generator = new MappingGenerator($file, 'test');
435+
$generator->reload(['test_index_1']);
436+
437+
$index = $this->connection->getIndex('test_index_1');
438+
$this->assertTrue($index->exists());
439+
440+
// Verify mapping was created with dynamic_templates
441+
$mapping = $index->getMapping();
442+
$this->assertNotEmpty($mapping);
443+
$this->assertArrayHasKey('properties', $mapping);
444+
$this->assertArrayHasKey('dynamic_templates', $mapping);
445+
446+
$dynamicTemplates = $mapping['dynamic_templates'];
447+
$this->assertCount(1, $dynamicTemplates);
448+
$this->assertArrayHasKey('strings_as_keywords', $dynamicTemplates[0]);
449+
450+
unlink($file);
451+
}
452+
453+
/**
454+
* Test mixing simple and full mapping formats in same file
455+
*/
456+
public function testMixedMappingFormats(): void
457+
{
458+
$file = $this->createMappingFile([
459+
[
460+
'name' => 'test_index_1',
461+
'mapping' => [
462+
'id' => ['type' => 'integer'],
463+
'title' => ['type' => 'text'],
464+
],
465+
],
466+
[
467+
'name' => 'test_index_2',
468+
'mapping' => [
469+
'properties' => [
470+
'id' => ['type' => 'integer'],
471+
'name' => ['type' => 'text'],
472+
],
473+
'dynamic' => 'strict',
474+
],
475+
],
476+
]);
477+
478+
$generator = new MappingGenerator($file, 'test');
479+
$generator->reload();
480+
481+
$index1 = $this->connection->getIndex('test_index_1');
482+
$index2 = $this->connection->getIndex('test_index_2');
483+
484+
$this->assertTrue($index1->exists());
485+
$this->assertTrue($index2->exists());
486+
487+
// Verify both mappings were created correctly
488+
$mapping1 = $index1->getMapping();
489+
$mapping2 = $index2->getMapping();
490+
491+
$this->assertNotEmpty($mapping1);
492+
$this->assertNotEmpty($mapping2);
493+
494+
$this->assertArrayHasKey('properties', $mapping1);
495+
$this->assertArrayHasKey('properties', $mapping2);
496+
$this->assertArrayHasKey('dynamic', $mapping2);
497+
498+
unlink($file);
499+
}
500+
335501
/**
336502
* Helper method to create a temporary mapping file
337503
*

0 commit comments

Comments
 (0)