NameMap.java
/*
Copyright (c) 2026 James Ahlborn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.healthmarketscience.jackcess;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import com.healthmarketscience.jackcess.query.Query;
/**
* A name map, the data behind the ms access "Name AutoCorrect" option. It
* holds a record for each table and column an object depends on, tied to the
* guid in the {@value PropertyMap#GUID_PROP} property of that table or
* column. When a table or column is renamed, ms access finds the old name
* here and changes the places which use it.
* <p>
* Two kinds of object carry one:
* <ul>
* <li>a table, in its {@value PropertyMap#NAME_MAP_PROP} property, which
* {@link Table#getNameMap} reads as a {@link TableNameMap}</li>
* <li>a query, in its {@value PropertyMap#QUERY_NAME_MAP_PROP} property,
* which {@link com.healthmarketscience.jackcess.query.Query#getNameMap}
* reads. It has a table record for each table or query the query uses
* and a column record for each column it uses. It cannot be changed, because
* ms access repairs a query when it finds a record whose guid now names an
* object with a different name, and a record changed without the sql of
* the query would stop that repair</li>
* </ul>
* Ms access does not require a name map, and nothing in jackcess updates one
* when a table changes, so the records can disagree with the database.
* {@link #findMismatches} lists where they do.
*
* @author James Ahlborn
* @usage _intermediate_class_
*/
public interface NameMap extends Iterable<NameMap.Record>
{
/**
* @return the table records, in the order of the name map
*/
public List<Record> getTableRecords();
/**
* @return the column records, in the order of the name map
*/
public List<Record> getColumnRecords();
/**
* @return the first table or column record with the given guid, or {@code
* null} if there is none
*/
public Record getRecord(String guid);
/**
* @return the tag in the end record, which is a value of the ms access
* build which wrote the name map, or {@code null} if the name map
* has no end record
*/
public Integer getWriterTag();
/**
* Compares the table and column records with the tables and columns they
* name.
*
* @return every difference, empty if the name map agrees with the database
*/
public List<Mismatch> findMismatches() throws IOException;
/**
* @return a Stream using the default Iterator.
*/
default public Stream<NameMap.Record> stream() {
return StreamSupport.stream(spliterator(), false);
}
/**
* The kinds of record in a name map.
*/
public enum RecordType
{
/** a table. A table name map has one, and it is the first record */
TABLE,
/** a name which an expression in a table uses */
REFERENCE,
/** a column */
COLUMN,
/** the end of the name map. Older builds of ms access did not write
it */
END,
/** a type jackcess does not know, which is kept as it was read */
UNKNOWN;
}
/**
* One record of a name map.
*/
public interface Record
{
public RecordType getType();
/**
* @return the guid of the object, or {@code null} for a record which
* names no object (a reference or the end record)
*/
public String getGuid();
/**
* @return the guid of the table, for a column or a reference record,
* otherwise {@code null}
*/
public String getParentGuid();
public String getName();
/**
* @throws UnsupportedOperationException if the name map belongs to a
* query
*/
public void setName(String name);
/**
* @return the date in a table record, otherwise {@code null}. It is the
* last modified date of the table when ms access wrote the name
* map: when it rewrote the name map of the table, or when it
* saved the query.
*/
public LocalDateTime getDate();
}
/**
* The kinds of difference between a name map and the database.
*/
public enum MismatchType
{
/** a column of the table which holds the name map has no record */
MISSING_RECORD,
/** a record names no table or column, by guid or by name */
MISSING_OBJECT,
/** the object with the guid of a record has a different name */
NAME_DIFFERS,
/** the object with the name of a record has a different guid */
GUID_DIFFERS;
}
/**
* One difference between a name map and the database.
*/
public interface Mismatch
{
public MismatchType getType();
/**
* @return the table the difference is in, or {@code null} if the record
* names a query or no table was found for it
*/
public Table getTable();
/**
* @return the query the difference is in, for a record of a query name
* map which names the query it reads, otherwise {@code null}
*/
public Query getQuery();
/**
* @return the column, or {@code null} if the difference is in a table
* record or no column was found for the record
*/
public Column getColumn();
/**
* @return the record, or {@code null} if the column has no record
*/
public Record getRecord();
}
}