> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Naming conventions

This section explains the naming conventions used when using remote databases with DirectQuery.

When DirectQuery is used, the application will dynamically convert all Datastore Field and Store Names into a remote version. The remote version of the
Datastore fields is what our remote database fields and tables should be named. If the Database and name mapper are out of sync, then the remote Tables/Fields
may not be discoverable by the application.

The interface `INameMapper` is used to convert Datastore field and store names into a format that works with remote databases.

## Reference DirectQueryNameMapper

The reference `DirectQueryNameMapper` class is responsible for converting names from one format into another. We use this to convert datastore fields or store
names into a name that is more compatible with remote databases. Since some databases have strict naming conventions, we have designed our
`DirectQueryNameMapper` to handle most database naming conventions.

The reference `DirectQueryNameMapper` works by taking a datastore name and converting it into one with the following logic:

* Entire name is converted to upper case
* Spaces are replaced with underscores '\_'
* CamelCase is split on the hump with underscores

So we can expect the following conversions to take place with the default `DirectQueryNameMapper`:

| Input (local datastore) Name | Output (remote database) Name | Note                               |
| ---------------------------- | ----------------------------- | ---------------------------------- |
| myvar                        | MYVAR                         | Set to uppercase                   |
| myVar                        | MY\_VAR                       | CamelCase                          |
| MYVar                        | MYVAR                         | No change (because not camel case) |
| MYVAR                        | MYVAR                         | No change                          |
| MY\_VAR                      | MY\_VAR                       | No change                          |
| my var                       | MY\_VAR                       | Space replaced with underscore     |

## Custom Naming Conventions

If you want to use custom naming conventions then you must create a custom implementation of the `INameMapper` interface and mark it as a spring
component using the `@Primary` annotation so that your implementation takes precedence over the reference`DirectQueryNameMapper`.
Then import your custom naming convention spring component into your ApplicationConfig (or into the `FRTBConfig` class).

### Custom Naming Convention Example

Here we create a custom naming convention that converts a given name into uppercase and replaces spaces with underscores '\_'.

First we create a function that will convert one way from the local name to the remote name:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
	private String localToRemoteName(String localName){
		return localName
				.toUpperCase()
				.replace(' ', '_');
	}
```

However, we will have difficulties when converting remote names to local names. To handle this we can cache the names that we have already converted and perform the calculation when our `CustomNameMapper` is created. We will use the `IDatastoreSchemaDescription` to help us with our pre-caching.

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Component
public class CustomNameMapper implements INameMapper {

	private IDatastoreSchemaDescription datastoreSchemaDescription;

	private final Map<String, String> localToRemoteNames = new HashMap<>();
	private final Map<String, String> remoteToLocalNames = new HashMap<>();

	public CustomNameMapper(IDatastoreSchemaDescription datastoreSchemaDescription){
		this.datastoreSchemaDescription = datastoreSchemaDescription;
		init();
	}

	private void init(){
		for (var datastoreDescription : datastoreSchemaDescription.getStoreDescriptions()){

			// Convert Datastore Name:
			String datastoreName = datastoreDescription.getName();
			initCacheFor(datastoreName);

			// Convert Datastore Fields:
			for(String fieldName : datastoreDescription.getKeyFields()){
				initCacheFor(fieldName);
			}
		}
	}

	private void initCacheFor(String localName){
		String remoteName = localToRemoteName(localName);

		localToRemoteNames.put(localName, remoteName);
		remoteToLocalNames.put(remoteName, localName);
	}

	private String localToRemoteName(String localName){
		return localName
				.toUpperCase()
				.replace(' ', '_');
	}
}
```

Now we can complete our class by implementing the methods from the interface:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Primary
@Component
public class CustomNameMapper implements INameMapper {

	private IDatastoreSchemaDescription datastoreSchemaDescription;

	private final Map<String, String> localToRemoteNames = new HashMap<>();
	private final Map<String, String> remoteToLocalNames = new HashMap<>();

	public CustomNameMapper(IDatastoreSchemaDescription datastoreSchemaDescription){
		this.datastoreSchemaDescription = datastoreSchemaDescription;
		init();
	}

	private void init(){
		for (var datastoreDescription : datastoreSchemaDescription.getStoreDescriptions()){

			// Convert Datastore Name:
			String datastoreName = datastoreDescription.getName();
			initCacheFor(datastoreName);

			// Convert Datastore Fields:
			for(String fieldName : datastoreDescription.getKeyFields()){
				initCacheFor(fieldName);
			}
		}
	}

	private void initCacheFor(String localName){
		String remoteName = localToRemoteName(localName);

		localToRemoteNames.put(localName, remoteName);
		remoteToLocalNames.put(remoteName, localName);
	}

	private String localToRemoteName(String localName){
		return localName
				.toUpperCase()
				.replace(' ', '_');
	}

	@Override public String convertToRemoteFieldName(String localStoreName, String localFieldName) {
		return localToRemoteNames.get(localFieldName);
	}

	@Override public String convertToLocalFieldName(String remoteTableName, String remoteFieldName) {
		return remoteToLocalNames.get(remoteFieldName);
	}

	@Override public String convertToRemoteFieldName(String localFieldName) {
		return localToRemoteNames.get(localFieldName);
	}

	@Override public String convertToLocalFieldName(String remoteFieldName) {
		return remoteToLocalNames.get(remoteFieldName);
	}

	@Override public String convertToRemoteTableName(String localStoreName) {
		return localToRemoteNames.get(localStoreName);
	}

	@Override public String convertToLocalStoreName(String remoteTableName) {
		return remoteToLocalNames.get(remoteTableName);
	}
}
```

Finally, we add our custom name mapper to our ApplicationConfig (or into the `FRTBConfig` class):

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@PropertySource(value = {
    ...
})
@Configuration
@Import(value = {
		...

		CustomNameMapper.class
})
public class FRTBConfig {
```
