Skip to content

Commit a1dc2f6

Browse files
authored
Merge pull request #185 from domaframework/feature/reference-doma-compile-config
Reference custom function definition class from config file
2 parents 031e708 + 5e60af6 commit a1dc2f6

File tree

41 files changed

+480
-494
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+480
-494
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,11 @@ Some functions of "Doma Tools" can be customized from the settings screen.
9797
- Customize action shortcut keys
9898
- Toggle the SQL formatting feature on or off
9999
- Specify the class names that define custom functions.
100-
![setting.png](images/setting.png)
100+
101+
**If you want to use custom functions defined in your own ExpressionFunctions implementation class,
102+
place a `doma.compile.config` file directly under the resources directory and describe the `doma.expr.functions` entry.**
103+
104+
ex) doma.compile.config
105+
```properties
106+
doma.expr.functions=example.expression.MyExpressionFunctions
107+
```

images/setting.png

-9.54 KB
Binary file not shown.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright Doma Tools Authors
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+
* https://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+
package org.domaframework.doma.intellij.common
17+
18+
import com.intellij.openapi.module.Module
19+
import com.intellij.openapi.roots.ModuleRootManager
20+
import com.intellij.openapi.vfs.VirtualFile
21+
import org.jetbrains.jps.model.java.JavaResourceRootType
22+
import org.jetbrains.jps.model.java.JavaSourceRootType
23+
import java.util.concurrent.ConcurrentHashMap
24+
25+
val RESOURCES_META_INF_PATH: String
26+
get() = "META-INF"
27+
28+
/**
29+
* A utility for caching directory information on a per-module basis.
30+
*/
31+
object CommonPathParameterUtil {
32+
/**
33+
* Holds directory information for a module.
34+
*
35+
* @property moduleBasePath The base path of the module.
36+
* @property moduleSourceDirectories List of source directories.
37+
* @property moduleResourceDirectories List of resource directories.
38+
* @property moduleTestSourceDirectories List of test source directories.
39+
* @property moduleTestResourceDirectories List of test resource directories.
40+
*/
41+
data class ModulePaths(
42+
val moduleBasePath: VirtualFile?,
43+
val moduleSourceDirectories: List<VirtualFile>,
44+
val moduleResourceDirectories: List<VirtualFile>,
45+
val moduleTestSourceDirectories: List<VirtualFile>,
46+
val moduleTestResourceDirectories: List<VirtualFile>,
47+
)
48+
49+
// Cache for each module's directory information.
50+
private val modulePathCache = ConcurrentHashMap<Module, ModulePaths>()
51+
52+
/**
53+
* Returns the directory information for the specified module (uses cache if available).
54+
* If the module's directory structure has changed, call [refreshModulePaths] to update the cache.
55+
*
56+
* @param module The module to retrieve directory information for.
57+
* @return The cached or newly computed ModulePaths.
58+
*/
59+
fun getModulePaths(module: Module): ModulePaths = modulePathCache[module] ?: refreshModulePaths(module)
60+
61+
/**
62+
* Refreshes the directory information for the specified module and updates the cache.
63+
* Call this method when the module's directory structure changes.
64+
*
65+
* @param module The module to refresh.
66+
* @return The updated ModulePaths.
67+
*/
68+
fun refreshModulePaths(module: Module): ModulePaths {
69+
var basePath: VirtualFile? = null
70+
val sourceDirs = mutableListOf<VirtualFile>()
71+
val resourceDirs = mutableListOf<VirtualFile>()
72+
val testSourceDirs = mutableListOf<VirtualFile>()
73+
val testResourceDirs = mutableListOf<VirtualFile>()
74+
75+
val moduleManager = ModuleRootManager.getInstance(module)
76+
moduleManager.contentEntries.firstOrNull()?.let { entry ->
77+
basePath = entry.file
78+
entry.sourceFolders.forEach { folder ->
79+
val file = folder.file
80+
if (file != null) {
81+
when (folder.rootType) {
82+
JavaSourceRootType.SOURCE -> sourceDirs.add(file)
83+
JavaSourceRootType.TEST_SOURCE -> testSourceDirs.add(file)
84+
JavaResourceRootType.RESOURCE -> resourceDirs.add(file)
85+
JavaResourceRootType.TEST_RESOURCE -> testResourceDirs.add(file)
86+
}
87+
}
88+
}
89+
}
90+
val paths =
91+
ModulePaths(
92+
basePath,
93+
sourceDirs,
94+
resourceDirs,
95+
testSourceDirs,
96+
testResourceDirs,
97+
)
98+
modulePathCache[module] = paths
99+
return paths
100+
}
101+
102+
/**
103+
* Determines if the given file belongs to a test source or test resource directory.
104+
*
105+
* @param module The module to check.
106+
* @param file The file to check.
107+
* @return True if the file is in a test directory, false otherwise.
108+
*/
109+
fun isTest(
110+
module: Module,
111+
file: VirtualFile,
112+
): Boolean {
113+
val paths = getModulePaths(module)
114+
if (paths.moduleTestSourceDirectories.any { file.path.contains(it.path) }) return true
115+
if (paths.moduleTestResourceDirectories.any { file.path.contains(it.path) }) return true
116+
return false
117+
}
118+
119+
/**
120+
* Returns the resource directories for the given file in the specified module.
121+
* If the file is in a test directory, test resource directories are returned.
122+
*
123+
* @param module The module to check.
124+
* @param file The file to check.
125+
* @return List of resource directories.
126+
*/
127+
fun getResources(
128+
module: Module,
129+
file: VirtualFile,
130+
): List<VirtualFile> =
131+
if (isTest(module, file)) {
132+
getModulePaths(module).moduleTestResourceDirectories
133+
} else {
134+
getModulePaths(module).moduleResourceDirectories
135+
}
136+
137+
/**
138+
* Returns the source directories for the given file in the specified module.
139+
* If the file is in a test directory, test source directories are returned.
140+
*
141+
* @param module The module to check.
142+
* @param file The file to check.
143+
* @return List of source directories.
144+
*/
145+
fun getSources(
146+
module: Module,
147+
file: VirtualFile,
148+
): List<VirtualFile> =
149+
if (isTest(module, file)) {
150+
getModulePaths(module).moduleTestSourceDirectories
151+
} else {
152+
getModulePaths(module).moduleSourceDirectories
153+
}
154+
155+
/**
156+
* Clears the module directory cache. Call this if the module structure changes.
157+
*/
158+
fun clearCache() {
159+
modulePathCache.clear()
160+
}
161+
}

src/main/kotlin/org/domaframework/doma/intellij/common/CommonPathParameterHelper.kt

Lines changed: 0 additions & 110 deletions
This file was deleted.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright Doma Tools Authors
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+
* https://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+
package org.domaframework.doma.intellij.common.config
17+
18+
import com.intellij.openapi.project.Project
19+
import com.intellij.openapi.vfs.VirtualFile
20+
import org.domaframework.doma.intellij.common.CommonPathParameterUtil
21+
import java.util.concurrent.ConcurrentHashMap
22+
23+
object DomaCompileConfigUtil {
24+
/**
25+
* Cache: key=file path, value=Pair<Properties, last update time>
26+
*/
27+
private val configCache = ConcurrentHashMap<String, Pair<java.util.Properties, Long>>()
28+
29+
/**
30+
* Get the value of the specified key from doma.compile.config
31+
* @param project active project
32+
* @param resourcePaths the path to the resource directories
33+
* @param key the key to retrieve the value for
34+
* @return the value associated with the key, or null if not found
35+
*/
36+
fun getConfigValue(
37+
project: Project,
38+
resourcePaths: List<VirtualFile>,
39+
key: String,
40+
): String? {
41+
resourcePaths.forEach { resourcePath ->
42+
if (resourcePath.isValid) {
43+
val configVFile = resourcePath.findChild("doma.compile.config")
44+
val cacheKey = "${project.basePath}/${resourcePath.path}/doma.compile.config"
45+
val lastModified = configVFile?.timeStamp ?: 0L
46+
val cached = configCache[cacheKey]
47+
48+
val props =
49+
if (cached == null || cached.second != lastModified) {
50+
val loadedProps =
51+
configVFile?.inputStream?.use { input ->
52+
java.util.Properties().apply { load(input) }
53+
} ?: java.util.Properties()
54+
configCache[cacheKey] = loadedProps to lastModified
55+
loadedProps
56+
} else {
57+
cached.first
58+
}
59+
val propProperty = props.getProperty(key)
60+
if (propProperty != null) return propProperty
61+
} else {
62+
CommonPathParameterUtil.clearCache()
63+
}
64+
}
65+
return null
66+
}
67+
}

0 commit comments

Comments
 (0)