View Javadoc
1   /*
2   Copyright (c) 2026 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess;
18  
19  import java.io.IOException;
20  import java.time.LocalDateTime;
21  import java.util.List;
22  import java.util.stream.Stream;
23  import java.util.stream.StreamSupport;
24  
25  import com.healthmarketscience.jackcess.query.Query;
26  
27  /**
28   * A name map, the data behind the ms access "Name AutoCorrect" option.  It
29   * holds a record for each table and column an object depends on, tied to the
30   * guid in the {@value PropertyMap#GUID_PROP} property of that table or
31   * column.  When a table or column is renamed, ms access finds the old name
32   * here and changes the places which use it.
33   * <p>
34   * Two kinds of object carry one:
35   * <ul>
36   * <li>a table, in its {@value PropertyMap#NAME_MAP_PROP} property, which
37   *     {@link Table#getNameMap} reads as a {@link TableNameMap}</li>
38   * <li>a query, in its {@value PropertyMap#QUERY_NAME_MAP_PROP} property,
39   *     which {@link com.healthmarketscience.jackcess.query.Query#getNameMap}
40   *     reads.  It has a table record for each table or query the query uses
41   *     and a column record for each column it uses.  It cannot be changed, because
42   *     ms access repairs a query when it finds a record whose guid now names an
43   *     object with a different name, and a record changed without the sql of
44   *     the query would stop that repair</li>
45   * </ul>
46   * Ms access does not require a name map, and nothing in jackcess updates one
47   * when a table changes, so the records can disagree with the database.
48   * {@link #findMismatches} lists where they do.
49   *
50   * @author James Ahlborn
51   * @usage _intermediate_class_
52   */
53  public interface NameMap extends Iterable<NameMap.Record>
54  {
55    /**
56     * @return the table records, in the order of the name map
57     */
58    public List<Record> getTableRecords();
59  
60    /**
61     * @return the column records, in the order of the name map
62     */
63    public List<Record> getColumnRecords();
64  
65    /**
66     * @return the first table or column record with the given guid, or {@code
67     *         null} if there is none
68     */
69    public Record getRecord(String guid);
70  
71    /**
72     * @return the tag in the end record, which is a value of the ms access
73     *         build which wrote the name map, or {@code null} if the name map
74     *         has no end record
75     */
76    public Integer getWriterTag();
77  
78    /**
79     * Compares the table and column records with the tables and columns they
80     * name.
81     *
82     * @return every difference, empty if the name map agrees with the database
83     */
84    public List<Mismatch> findMismatches() throws IOException;
85  
86    /**
87     * @return a Stream using the default Iterator.
88     */
89    default public Stream<NameMap.Record> stream() {
90      return StreamSupport.stream(spliterator(), false);
91    }
92  
93    /**
94     * The kinds of record in a name map.
95     */
96    public enum RecordType
97    {
98      /** a table.  A table name map has one, and it is the first record */
99      TABLE,
100     /** a name which an expression in a table uses */
101     REFERENCE,
102     /** a column */
103     COLUMN,
104     /** the end of the name map.  Older builds of ms access did not write
105         it */
106     END,
107     /** a type jackcess does not know, which is kept as it was read */
108     UNKNOWN;
109   }
110 
111   /**
112    * One record of a name map.
113    */
114   public interface Record
115   {
116     public RecordType getType();
117 
118     /**
119      * @return the guid of the object, or {@code null} for a record which
120      *         names no object (a reference or the end record)
121      */
122     public String getGuid();
123 
124     /**
125      * @return the guid of the table, for a column or a reference record,
126      *         otherwise {@code null}
127      */
128     public String getParentGuid();
129 
130     public String getName();
131 
132     /**
133      * @throws UnsupportedOperationException if the name map belongs to a
134      *         query
135      */
136     public void setName(String name);
137 
138     /**
139      * @return the date in a table record, otherwise {@code null}.  It is the
140      *         last modified date of the table when ms access wrote the name
141      *         map: when it rewrote the name map of the table, or when it
142      *         saved the query.
143      */
144     public LocalDateTime getDate();
145   }
146 
147   /**
148    * The kinds of difference between a name map and the database.
149    */
150   public enum MismatchType
151   {
152     /** a column of the table which holds the name map has no record */
153     MISSING_RECORD,
154     /** a record names no table or column, by guid or by name */
155     MISSING_OBJECT,
156     /** the object with the guid of a record has a different name */
157     NAME_DIFFERS,
158     /** the object with the name of a record has a different guid */
159     GUID_DIFFERS;
160   }
161 
162   /**
163    * One difference between a name map and the database.
164    */
165   public interface Mismatch
166   {
167     public MismatchType getType();
168 
169     /**
170      * @return the table the difference is in, or {@code null} if the record
171      *         names a query or no table was found for it
172      */
173     public Table getTable();
174 
175     /**
176      * @return the query the difference is in, for a record of a query name
177      *         map which names the query it reads, otherwise {@code null}
178      */
179     public Query getQuery();
180 
181     /**
182      * @return the column, or {@code null} if the difference is in a table
183      *         record or no column was found for the record
184      */
185     public Column getColumn();
186 
187     /**
188      * @return the record, or {@code null} if the column has no record
189      */
190     public Record getRecord();
191   }
192 }