limitsdb 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- limitsdb/__init__.py +0 -0
- limitsdb/cli/__init__.py +0 -0
- limitsdb/cli/ldb_crypt.py +44 -0
- limitsdb/cli/ldb_impl.py +207 -0
- limitsdb/cli/ldb_init.py +60 -0
- limitsdb/cli/ldb_run.py +53 -0
- limitsdb/core/__init__.py +0 -0
- limitsdb/core/ldb_config_loader.py +198 -0
- limitsdb/core/ldb_crypto.py +91 -0
- limitsdb/core/ldb_errors.py +30 -0
- limitsdb/core/ldb_ilm_config.py +228 -0
- limitsdb/core/ldb_logger.py +57 -0
- limitsdb/core/ldb_meta.py +31 -0
- limitsdb/core/ldb_params_config.py +459 -0
- limitsdb/core/ldb_runner.py +810 -0
- limitsdb/core/ldb_status.py +8 -0
- limitsdb/core/ldb_utils.py +332 -0
- limitsdb/db/__init__.py +0 -0
- limitsdb/db/ldb_engine_loader.py +16 -0
- limitsdb/db/ldb_engines.py +347 -0
- limitsdb/db/oracle/__init__.py +0 -0
- limitsdb/db/oracle/ldb_conf.sql +151 -0
- limitsdb/db/oracle/ldb_engine_impl.py +1505 -0
- limitsdb/resources/__init__.py +0 -0
- limitsdb/resources/ilm.example.yml +71 -0
- limitsdb-0.5.0.dist-info/METADATA +586 -0
- limitsdb-0.5.0.dist-info/RECORD +32 -0
- limitsdb-0.5.0.dist-info/WHEEL +4 -0
- limitsdb-0.5.0.dist-info/entry_points.txt +6 -0
- limitsdb-0.5.0.dist-info/licenses/LICENSE +118 -0
- limitsdb-0.5.0.dist-info/licenses/LICENSE-DUAL.md +59 -0
- limitsdb-0.5.0.dist-info/licenses/NOTICE +12 -0
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# For example: source_owner, history_owner, table_name, source_orphan_purge
|
|
2
|
+
# All database identifiers in keys values must follow database identifier rules:
|
|
3
|
+
# unquoted → normalized by engine; quoted → case-sensitive and may include special characters.
|
|
4
|
+
# Example: "@inv_dsp_date" → normalized name, '@"inv_dsp_date"' → exact name
|
|
5
|
+
# For examples:
|
|
6
|
+
# source_owner: GL # unquoted, normalized by engine
|
|
7
|
+
# source_owner: '"Gl" # quoted, exact name: Gl
|
|
8
|
+
# source_owner: "\"gL*\"" # quoted, exact name with special characters: gL*
|
|
9
|
+
# source_additional_filter_expr: "@\"INV_STATUS\"='D'" # quoted column name, normalized by engine
|
|
10
|
+
#
|
|
11
|
+
# Example ILM configuration file
|
|
12
|
+
#
|
|
13
|
+
# tables: # List of tables to apply ILM
|
|
14
|
+
# - source_owner: GL # Source owner of table (must match DD case)
|
|
15
|
+
# history_owner: GLHST # History owner of table (must match DD case)
|
|
16
|
+
# table_name: INV_HEAD # Table name. In this example this is a parent table (must match DD case)
|
|
17
|
+
# frecuency: D # Frecuency of ILM application. Expected values (D: dayly, M: monthly)
|
|
18
|
+
# hint_expr: full(A) # Hint to apply in selection from source table. Use table alias A for source table and B, C, etc for referenced tables
|
|
19
|
+
# conds: # List of conditions for selection
|
|
20
|
+
# - is_active: true # if condition is active
|
|
21
|
+
# retain_months_source: 3 # Months to retain in source
|
|
22
|
+
# retain_months_history: 11 # Months to retain in history after transfered to history env. If 0 or undefined there will be no history, only source deletion
|
|
23
|
+
# purge_date_expr: "@INV_DSP_DATE" # Date expression for ILM to compare with. Columns must be marked @ preffix. (must follow DB identifier rules)
|
|
24
|
+
# source_additional_filter_expr: "@INV_STATUS='D'" # Optional additional expression to apply in ILM selection. (must follow DB identifier rules)
|
|
25
|
+
# - is_active: true # Another condition. Can differ in any definition of other conditions of same table
|
|
26
|
+
# retain_months_source: 1
|
|
27
|
+
# retain_months_history: 0
|
|
28
|
+
# purge_date_expr: "@INVD_DATE"
|
|
29
|
+
# source_additional_filter_expr: "@INV_STATUS='A'"
|
|
30
|
+
# history_addtl_filter_expr: "@INV_STATUS='H'" # Optional history-only expression. Falls back to additional_filter_expr when omitted. (must follow DB identifier rules)
|
|
31
|
+
# - source_owner: GL # Child table definition. Inherit conditions from parent tables. Can have multiple parent tables
|
|
32
|
+
# history_owner: GL
|
|
33
|
+
# table_name: INV_DET
|
|
34
|
+
# frecuency: D
|
|
35
|
+
# hint_expr: full(A) full(B) use_hash(A, B)
|
|
36
|
+
# history_hint_expr: full(A)
|
|
37
|
+
# referencing_tables: INV_HEAD B # List of parent tables
|
|
38
|
+
# join_expr: "@ JOIN GL.INV_HEAD B ON B.INV_ID=A.INV_ID" # Join expression to link to parent table (must follow DB identifier rules)
|
|
39
|
+
# source_orphan_purge: true # Archive source rows whose referenced parent is absent; requires use_added_columns: true
|
|
40
|
+
# orphan_check_column: B.INV_ID # Parent column checked with IS NULL after the left outer join
|
|
41
|
+
# # conds:
|
|
42
|
+
# # - is_active: true # If a table with no conds but an explicit inactive one is considered inactive
|
|
43
|
+
# - source_owner: GL # Parent table
|
|
44
|
+
# history_owner: GL
|
|
45
|
+
# table_name: DSP_HEAD
|
|
46
|
+
# frecuency: D
|
|
47
|
+
# hint_expr: full(A)
|
|
48
|
+
# conds:
|
|
49
|
+
# - is_active: true
|
|
50
|
+
# retain_months_source: 3
|
|
51
|
+
# retain_months_history: 0
|
|
52
|
+
# purge_date_expr: "@DSP_DATE"
|
|
53
|
+
# additional_filter_expr: "@DSP_STATUS='D'"
|
|
54
|
+
# - is_active: true
|
|
55
|
+
# retain_months_source: 1
|
|
56
|
+
# retain_months_history: 0
|
|
57
|
+
# purge_date_expr: "@DSP_DATE"
|
|
58
|
+
# additional_filter_expr: "@DSP_STATUS='A'"
|
|
59
|
+
# - source_owner: GL # Child table with three parent tables. Inherite conditions of all parent tables
|
|
60
|
+
# history_owner: GL
|
|
61
|
+
# table_name: DSP_DET
|
|
62
|
+
# frecuency: D
|
|
63
|
+
# hint_expr: full(A) full(B) full(C) full(D) use_hash(A, B, C, D)
|
|
64
|
+
# history_hint_expr: full(A)
|
|
65
|
+
# referencing_tables: GL.DSP_HEAD B, GL.INV_DET C, GL.INV_HEAD D
|
|
66
|
+
# join_expr: "@ JOIN GL.DSP_HEAD B ON B.DSP_ID=A.DSP_ID @ JOIN GL.INV_DET C ON C.IND_ID = A.IND_ID @ JOIN GL.INV_HEAD ON D.INV_ID= C.INV_ID"
|
|
67
|
+
# source_orphan_purge: true
|
|
68
|
+
# orphan_check_column: B.DSP_ID, C.IND_ID, D.INV_ID # Any NULL check marks the source row as orphaned
|
|
69
|
+
# has_lob_columns: true
|
|
70
|
+
# conds:
|
|
71
|
+
# # - is_active: true
|
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: limitsdb
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Configuration-driven ILM (Information Lifecycle Management) for production and history databases
|
|
5
|
+
License: Apache License
|
|
6
|
+
Version 2.0, January 2004
|
|
7
|
+
http://www.apache.org/licenses/
|
|
8
|
+
|
|
9
|
+
Copyright © 2025 Inversiones Etimo SpA and contributors
|
|
10
|
+
|
|
11
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
you may not use this file except in compliance with the License.
|
|
13
|
+
You may obtain a copy of the License at
|
|
14
|
+
|
|
15
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
|
|
17
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
18
|
+
|
|
19
|
+
1. Definitions.
|
|
20
|
+
|
|
21
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
22
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
23
|
+
|
|
24
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
25
|
+
the copyright owner that is granting the License.
|
|
26
|
+
|
|
27
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
28
|
+
other entities that control, are controlled by, or are under common
|
|
29
|
+
control with that entity.
|
|
30
|
+
|
|
31
|
+
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
|
32
|
+
permissions granted by this License.
|
|
33
|
+
|
|
34
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
35
|
+
including but not limited to software source code, documentation
|
|
36
|
+
source, and configuration files.
|
|
37
|
+
|
|
38
|
+
"Object" form shall mean any form resulting from mechanical
|
|
39
|
+
transformation or translation of a Source form.
|
|
40
|
+
|
|
41
|
+
"Work" shall mean the work of authorship made available under the
|
|
42
|
+
License, as indicated by a copyright notice that is included in or
|
|
43
|
+
attached to the work.
|
|
44
|
+
|
|
45
|
+
"Derivative Works" shall mean any work that is based on (or derived
|
|
46
|
+
from) the Work and for which the editorial revisions, annotations,
|
|
47
|
+
elaborations, or other modifications represent, as a whole, an
|
|
48
|
+
original work of authorship.
|
|
49
|
+
|
|
50
|
+
"Contribution" shall mean any work of authorship submitted to the
|
|
51
|
+
Licensor for inclusion in the Work.
|
|
52
|
+
|
|
53
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
54
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
55
|
+
subsequently incorporated within the Work.
|
|
56
|
+
|
|
57
|
+
2. Grant of Copyright License.
|
|
58
|
+
|
|
59
|
+
Subject to the terms and conditions of this License, each Contributor
|
|
60
|
+
hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
61
|
+
no-charge, royalty-free, irrevocable copyright license to reproduce,
|
|
62
|
+
prepare Derivative Works of, publicly display, publicly perform,
|
|
63
|
+
sublicense, and distribute the Work and such Derivative Works in
|
|
64
|
+
Source or Object form.
|
|
65
|
+
|
|
66
|
+
3. Grant of Patent License.
|
|
67
|
+
|
|
68
|
+
Subject to the terms and conditions of this License, each Contributor
|
|
69
|
+
hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
70
|
+
no-charge, royalty-free, irrevocable patent license to make, have
|
|
71
|
+
made, use, offer to sell, sell, import, and otherwise transfer the
|
|
72
|
+
Work.
|
|
73
|
+
|
|
74
|
+
4. Redistribution.
|
|
75
|
+
|
|
76
|
+
You may reproduce and distribute copies of the Work or Derivative
|
|
77
|
+
Works thereof in any medium, with or without modifications, and in
|
|
78
|
+
Source or Object form, provided that You meet the following
|
|
79
|
+
conditions:
|
|
80
|
+
|
|
81
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
82
|
+
Works a copy of this License; and
|
|
83
|
+
|
|
84
|
+
(b) You must cause any modified files to carry prominent notices
|
|
85
|
+
stating that You changed the files; and
|
|
86
|
+
|
|
87
|
+
(c) You must retain, in the Source form of any Derivative Works that
|
|
88
|
+
You distribute, all copyright, patent, trademark, and attribution
|
|
89
|
+
notices from the Source form of the Work; and
|
|
90
|
+
|
|
91
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
92
|
+
distribution, then any Derivative Works that You distribute must
|
|
93
|
+
include a readable copy of the attribution notices contained within
|
|
94
|
+
such NOTICE file.
|
|
95
|
+
|
|
96
|
+
5. Submission of Contributions.
|
|
97
|
+
|
|
98
|
+
Unless You explicitly state otherwise, any Contribution intentionally
|
|
99
|
+
submitted for inclusion in the Work by You to the Licensor shall be
|
|
100
|
+
under the terms and conditions of this License.
|
|
101
|
+
|
|
102
|
+
6. Trademarks.
|
|
103
|
+
|
|
104
|
+
This License does not grant permission to use the trade names,
|
|
105
|
+
trademarks, service marks, or product names of the Licensor.
|
|
106
|
+
|
|
107
|
+
7. Disclaimer of Warranty.
|
|
108
|
+
|
|
109
|
+
Unless required by applicable law or agreed to in writing, Licensor
|
|
110
|
+
provides the Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
111
|
+
CONDITIONS OF ANY KIND.
|
|
112
|
+
|
|
113
|
+
8. Limitation of Liability.
|
|
114
|
+
|
|
115
|
+
In no event shall any Contributor be liable to You for damages arising
|
|
116
|
+
from the use of the Work.
|
|
117
|
+
|
|
118
|
+
9. Accepting Warranty or Additional Liability.
|
|
119
|
+
|
|
120
|
+
While redistributing the Work or Derivative Works thereof, You may
|
|
121
|
+
choose to offer support, warranty, indemnity, or other liability
|
|
122
|
+
obligations and/or rights consistent with this License.
|
|
123
|
+
License-File: LICENSE
|
|
124
|
+
License-File: LICENSE-DUAL.md
|
|
125
|
+
License-File: NOTICE
|
|
126
|
+
Keywords: database,oracle,ilm,data lifecycle,archiving
|
|
127
|
+
Author: Gustavo Cantizano
|
|
128
|
+
Author-email: gustavo.cantizano@etimo.cl
|
|
129
|
+
Maintainer: Inversiones Etimo SpA
|
|
130
|
+
Maintainer-email: contacto@etimo.cl
|
|
131
|
+
Requires-Python: >=3.12,<4.0
|
|
132
|
+
Classifier: Programming Language :: Python :: 3
|
|
133
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
134
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
135
|
+
Classifier: Operating System :: OS Independent
|
|
136
|
+
Classifier: Topic :: Database
|
|
137
|
+
Classifier: Topic :: System :: Systems Administration
|
|
138
|
+
Requires-Dist: cryptography (>=46.0.2,<47.0.0)
|
|
139
|
+
Requires-Dist: oracledb (>=2.5.1,<3.0.0)
|
|
140
|
+
Requires-Dist: platformdirs (>=4.5.0,<5.0.0)
|
|
141
|
+
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
|
142
|
+
Project-URL: Homepage, https://github.com/etimochile/limitsdb
|
|
143
|
+
Project-URL: Issues, https://github.com/etimochile/limitsdb/issues
|
|
144
|
+
Project-URL: Repository, https://github.com/etimochile/limitsdb
|
|
145
|
+
Description-Content-Type: text/markdown
|
|
146
|
+
|
|
147
|
+
# LimitsDb
|
|
148
|
+
|
|
149
|
+
Configuration-driven ILM (Information Lifecycle Management) runner for operational databases. It applies retention policies to your application tables—archiving, purging, and keeping datasets lean—so source stays fast while history remains auditable. LimitsDb is designed to support multiple database engines; **Oracle** is supported today, with an engine-agnostic ILM model that can extend to others.
|
|
150
|
+
|
|
151
|
+
## Overview (What it does)
|
|
152
|
+
|
|
153
|
+
- **Executes ILM policies on real schemas.** You describe which tables are in scope, how they relate (parents/children), and the rules that decide when rows move to history or are purged.
|
|
154
|
+
- **Targets source and history environments.** Choose whether to act on **source** (move/purge) or **history** (downstream cleanup) for the same ILM model.
|
|
155
|
+
- **Retains exactly what you need.** Per-table, per-condition retention windows (e.g., “keep 3 months in source, 11 months in history”), with the ability to define multiple conditions per table.
|
|
156
|
+
- **Understands relationships.** Reference parent tables, define join expressions, and optionally purge **orphans** when child rows lose their parent.
|
|
157
|
+
- **Handles heavy tables safely.** Chunked processing and parallelism keep large operations predictable and observable.
|
|
158
|
+
- **Works with hints and special cases.** Add optimizer hints, mark LOB-heavy tables, and tune behavior per table.
|
|
159
|
+
- **Dry-run anytime.** Generate the exact operations without executing them, to review and approve planned changes.
|
|
160
|
+
- **Keeps secrets safe.** Database credentials are stored encrypted and transparently decrypted at runtime.
|
|
161
|
+
- **Automates control DB objects creation.** Creates missing control schemas and DB objects.
|
|
162
|
+
- **Automates history objects creation and updates.** Creates missing history tables and correct columns, contraints and indexes for ILM executions.
|
|
163
|
+
|
|
164
|
+
### Typical outcomes
|
|
165
|
+
|
|
166
|
+
- **Slimmer source**: old/inactive rows are moved or purged on a schedule.
|
|
167
|
+
- **Auditable history**: history schemas keep what you configure, for the period you define.
|
|
168
|
+
- **Predictable cost/perf**: smaller hot datasets, fewer full-table scans, faster maintenance windows.
|
|
169
|
+
|
|
170
|
+
### How you use it (at a glance)
|
|
171
|
+
|
|
172
|
+
1. **Model your ILM**: list the tables, joins to parents, and one or more conditions with retention windows and optional filters.
|
|
173
|
+
2. **Choose the target**: run against **SOURCE_ILM** (move/purge in source) or **HISTORY_ILM** (history-side cleanup).
|
|
174
|
+
3. **Run safely**: start with **Query-only / Dry-run** to review the actions; then run for real.
|
|
175
|
+
4. **Repeat** on your preferred cadence (via scheduler/cron or your release pipeline).
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Requirements
|
|
180
|
+
|
|
181
|
+
- **Python**: 3.12+ — https://www.python.org/downloads/
|
|
182
|
+
- **Oracle**: `oracledb` runs in thin mode (pure Python, no Oracle Instant Client required).
|
|
183
|
+
- **PostgreSQL**: planned for a future adapter; not currently accepted in configuration.
|
|
184
|
+
|
|
185
|
+
## Installation
|
|
186
|
+
|
|
187
|
+
### Recommended — pipx (no virtual environment management needed)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
pip install pipx
|
|
191
|
+
pipx install limitsdb
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`pipx` creates and manages the virtual environment automatically. After installation,
|
|
195
|
+
`ldb-run`, `ldb-impl`, `ldb-crypt`, and `ldb-init` are available in your terminal
|
|
196
|
+
on any platform without activation.
|
|
197
|
+
|
|
198
|
+
### Alternative — pip with a virtual environment
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
python -m venv .venv
|
|
202
|
+
# Windows:
|
|
203
|
+
.venv\Scripts\activate
|
|
204
|
+
# macOS / Linux:
|
|
205
|
+
source .venv/bin/activate
|
|
206
|
+
|
|
207
|
+
pip install limitsdb
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
For development setup (cloning the repo, running tests, CI) see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
211
|
+
|
|
212
|
+
## Quickstart
|
|
213
|
+
|
|
214
|
+
Spin up a minimal end-to-end run with the built-in scaffolding tools:
|
|
215
|
+
|
|
216
|
+
1. **Create config files** for a schema/profile pair:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
ldb-init --schema billing --profile dev
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
2. **Fill in connection details** in `~/.config/LimitsDb/schemas/billing/config.dev.yml` and secrets in `secrets.dev.json`.
|
|
223
|
+
|
|
224
|
+
3. **Encrypt secrets** in place:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
ldb-crypt --schema billing --profile dev
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
4. **Dry-run the ILM plan** (no data changes):
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
ldb-run --schema billing --profile dev --action SOURCE_ILM --mode PREVIEW
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
5. **Execute for real** once you are satisfied with the plan:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
ldb-run --schema billing --profile dev --action SOURCE_ILM --mode EXECUTE
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## CLI Commands
|
|
243
|
+
|
|
244
|
+
After installation, the following commands are available directly in your terminal:
|
|
245
|
+
|
|
246
|
+
- `ldb-init` — scaffold configuration files for a named configuration set
|
|
247
|
+
- `ldb-crypt` — encrypt cleartext secrets in place
|
|
248
|
+
- `ldb-impl` — verify and create DB control schemas and objects
|
|
249
|
+
- `ldb-run` — main ILM runner
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
ldb-init --help
|
|
253
|
+
ldb-crypt --help
|
|
254
|
+
ldb-impl --help
|
|
255
|
+
ldb-run --help
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Initialize Configuration
|
|
259
|
+
|
|
260
|
+
Scaffold the configuration files for a named configuration set and optional environment:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
ldb-init --schema <SCHEMA> [--profile <PROFILE>] [--config-dir <DIR>] [--overwrite] [--no-examples]
|
|
264
|
+
# examples:
|
|
265
|
+
# ldb-init --schema billing
|
|
266
|
+
# ldb-init --schema billing --profile prod
|
|
267
|
+
# ldb-init --schema billing --profile dev --config-dir /etc/limitsdb
|
|
268
|
+
# ldb-init --schema billing --profile dev --no-examples
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`--schema` is a name you choose to group all configuration files for one
|
|
272
|
+
system or application (e.g., `billing`, `crm`). It is not a database schema;
|
|
273
|
+
it is simply the folder name under which the files live.
|
|
274
|
+
|
|
275
|
+
`--profile` is optional. Use it when the same configuration set targets
|
|
276
|
+
multiple environments (e.g., `dev`, `prod`). When supplied, the profile name
|
|
277
|
+
becomes part of every file name as `.<PROFILE>`. When omitted, file names carry
|
|
278
|
+
no extra suffix.
|
|
279
|
+
|
|
280
|
+
`--overwrite` replaces existing files. Without it, any file that already exists
|
|
281
|
+
is left unchanged; only missing files are created.
|
|
282
|
+
|
|
283
|
+
`--no-examples` skips copying the ILM example file (`ilm[.<PROFILE>].example.yml`).
|
|
284
|
+
|
|
285
|
+
`--config-dir` scaffolds under a custom root instead of `~/.config/LimitsDb`.
|
|
286
|
+
|
|
287
|
+
Generated files (default root is `~/.config/LimitsDb`):
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
~/.config/LimitsDb/
|
|
291
|
+
└─ schemas/
|
|
292
|
+
└─ <SCHEMA>/
|
|
293
|
+
├─ config[.<PROFILE>].yml # commented defaults + help (from the Config model)
|
|
294
|
+
├─ ilm[.<PROFILE>].yml # empty list (you fill it)
|
|
295
|
+
├─ ilm[.<PROFILE>].example.yml # example copied verbatim from the package
|
|
296
|
+
└─ secrets[.<PROFILE>].json # secret fields with empty values
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Secrets & Encryption
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
ldb-crypt --schema <SCHEMA> [--profile <PROFILE>] [--config-dir <DIR>]
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
1. Edit `secrets[.<PROFILE>].json` and fill in the credentials:
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"source_password": "",
|
|
310
|
+
"history_password": "",
|
|
311
|
+
"admin_source_password": "",
|
|
312
|
+
"admin_history_password": ""
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
2. Encrypt in place:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
ldb-crypt --schema billing --profile prod
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`ldb-crypt` creates or reuses a local encryption key and replaces every
|
|
323
|
+
non-empty plaintext value in `secrets[.<PROFILE>].json` with an
|
|
324
|
+
`enc:v1:aes256gcm:…` token. Already-encrypted values are left unchanged.
|
|
325
|
+
If this step is skipped, `ldb-run` and `ldb-impl` will encrypt any plaintext
|
|
326
|
+
secrets automatically before the first run, provided the secrets file is in the
|
|
327
|
+
default user configuration directory or an explicit `--config-dir` is supplied.
|
|
328
|
+
`ldb-crypt` is a convenience to encrypt them without executing ILM.
|
|
329
|
+
|
|
330
|
+
The encryption key is stored in your user context and protected by OS
|
|
331
|
+
permissions. Never version or copy the key file.
|
|
332
|
+
|
|
333
|
+
## Bootstrap Database Objects
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
ldb-impl --schema <SCHEMA> [--profile <PROFILE>] [--config-dir <DIR>] [--config-file <YAML>] [--set key=value] [--log-level LEVEL]
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`ldb-impl` creates the database objects that LimitsDb needs to operate. Run it
|
|
340
|
+
once before the first `ldb-run`, and again whenever a new environment is
|
|
341
|
+
provisioned. All operations are idempotent: existing objects are left unchanged
|
|
342
|
+
and only missing ones are created.
|
|
343
|
+
|
|
344
|
+
**`ldb-impl` is optional** if a DBA has already created all required objects
|
|
345
|
+
manually. LimitsDb does not require objects to have been created through
|
|
346
|
+
`ldb-impl`; it only requires that the objects exist with the expected structure
|
|
347
|
+
before `ldb-run` is executed.
|
|
348
|
+
|
|
349
|
+
What it creates in both source and history environments:
|
|
350
|
+
|
|
351
|
+
- **Role** — grants the application user the privileges required by LimitsDb.
|
|
352
|
+
- **User** — the application user with its default tablespace and role.
|
|
353
|
+
- **Control tables** — `LDB_CTL` (execution state per table) and `LDB_LOG`
|
|
354
|
+
(audit log of each run).
|
|
355
|
+
- **Sequence** — `LDB_LOG_ID` for audit log identifiers.
|
|
356
|
+
- **Database link** — bidirectional links between source and history so the ILM
|
|
357
|
+
engine can reach both environments from either side.
|
|
358
|
+
|
|
359
|
+
`ldb-impl` requires all four credential pairs to be present and encrypted in
|
|
360
|
+
`secrets[.<PROFILE>].json`: `source_password`, `history_password`,
|
|
361
|
+
`admin_source_password`, and `admin_history_password`. Run `ldb-crypt` first.
|
|
362
|
+
|
|
363
|
+
## Run ILM
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
ldb-run --schema <SCHEMA> [--profile <PROFILE>] --action SOURCE_ILM|HISTORY_ILM [options]
|
|
367
|
+
# examples:
|
|
368
|
+
# ldb-run --schema billing --profile prod --action SOURCE_ILM
|
|
369
|
+
# ldb-run --schema billing --action HISTORY_ILM
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Common overrides:
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
--mode VALIDATE|PLAN|PREVIEW|SCRIPT|EXECUTE # VALIDATE setup, PLAN DAG, PREVIEW simulate, SCRIPT emit SQL, EXECUTE run
|
|
376
|
+
--chunk-size <int> # Rows per chunk when processing large tables
|
|
377
|
+
--parallel-max <int> # Maximum number of tables processed in parallel
|
|
378
|
+
--log-level DEBUG|INFO|WARNING|ERROR|CRITICAL # Adjust logger verbosity
|
|
379
|
+
--ilm-config-file <path> # Point to a specific ILM YAML file
|
|
380
|
+
--config-dir <root> # Override config root discovery
|
|
381
|
+
--config-file <yaml> # Extra overlay (highest priority)
|
|
382
|
+
--set key=value # Generic override (supports dotted keys)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Examples:
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Dry-run with verbose logging
|
|
389
|
+
ldb-run --schema billing --profile prod --action SOURCE_ILM --mode PREVIEW --log-level DEBUG
|
|
390
|
+
|
|
391
|
+
# Apply quick overrides without editing files
|
|
392
|
+
ldb-run --schema billing --profile prod --action SOURCE_ILM --mode EXECUTE --set chunk_size=200000 --set parallel_max=8
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Admin credentials in ldb-run
|
|
396
|
+
|
|
397
|
+
`ldb-run` uses admin credentials (`admin_source_password`,
|
|
398
|
+
`admin_history_password`) for two operations: granting table privileges to the
|
|
399
|
+
application role, and creating or altering history tables before an `EXECUTE`
|
|
400
|
+
run. Both operations are idempotent.
|
|
401
|
+
|
|
402
|
+
If admin credentials are absent from `secrets[.<PROFILE>].json`, the privilege
|
|
403
|
+
grants are skipped silently — the assumption is that grants are already in
|
|
404
|
+
place. History table management in `EXECUTE` mode still requires admin
|
|
405
|
+
credentials in the current version.
|
|
406
|
+
|
|
407
|
+
### Configuration parameters reference
|
|
408
|
+
|
|
409
|
+
| Parameter | Purpose | Default / values |
|
|
410
|
+
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
411
|
+
| `action` | ILM target (`SOURCE_ILM` moves/purges source, `HISTORY_ILM` cleans downstream history). | Default `SOURCE_ILM`; choices `SOURCE_ILM`, `HISTORY_ILM`. |
|
|
412
|
+
| `mode` | Execution mode: `VALIDATE` config/credentials, `PLAN` dependency order, `PREVIEW` simulate (a.k.a. legacy `DRY_RUN`), `SCRIPT` emit SQL, `EXECUTE` run changes. | Default `PREVIEW`; choices `VALIDATE`, `PLAN`, `PREVIEW`, `SCRIPT`, `EXECUTE`. |
|
|
413
|
+
| `chunk_size` | Rows per chunk when processing large tables. | Default `100000`. |
|
|
414
|
+
| `use_added_columns` | Populate derived columns in history tables. | Default `True` (boolean toggle). |
|
|
415
|
+
| `add_ldb_columns` | Add LimitsDb execution-date columns in history tables. | Default `True` (boolean toggle). |
|
|
416
|
+
| `parallel_max` | Maximum number of parallel processes. | Default `10`. |
|
|
417
|
+
| `db_engine` | Database engine. | Default and only current choice: `"oracle"`. |
|
|
418
|
+
| `log_level` | Logging level. | Default `"INFO"`; choices `"DEBUG"`, `"INFO"`, `"WARNING"`, `"ERROR"`, `"CRITICAL"`. |
|
|
419
|
+
| `schema` | Configuration set name: identifies a system or application (e.g., `billing`). Not a database schema — it is the folder that groups all configuration files for one target. | Required on CLI; no persisted default. |
|
|
420
|
+
| `profile` | Environment name (e.g., `dev`, `prod`). Differentiates configuration files for different environments within the same configuration set. | Optional; default `null`. |
|
|
421
|
+
| `ilm_config_file` | YAML file with tables (bypass DB discovery). | Optional; default `null`. |
|
|
422
|
+
| `source_dsn` | Source DSN / connection descriptor. | Default empty string. |
|
|
423
|
+
| `source_username` | Source username. | Default empty string. |
|
|
424
|
+
| `source_password` | Source password stored in secrets. | Default empty string; encrypted in `secrets.<PROFILE>.json`. |
|
|
425
|
+
| `history_dsn` | History DSN / connection descriptor. | Default empty string. |
|
|
426
|
+
| `history_username` | History username. | Default empty string. |
|
|
427
|
+
| `history_password` | History password stored in secrets. | Default empty string; encrypted in `secrets.<PROFILE>.json`. |
|
|
428
|
+
| `admin_source_username` | Admin source username. | Default empty string. |
|
|
429
|
+
| `admin_source_password` | Admin source password stored in secrets. | Default empty string; encrypted in `secrets.<PROFILE>.json`. |
|
|
430
|
+
| `admin_history_username` | Admin history username. | Default empty string. |
|
|
431
|
+
| `admin_history_password` | Admin history password stored in secrets. | Default empty string; encrypted in `secrets.<PROFILE>.json`. |
|
|
432
|
+
|
|
433
|
+
#### Overrides matrix (CLI, env, YAML)
|
|
434
|
+
|
|
435
|
+
| Parameter | CLI flag | Environment variable | YAML key |
|
|
436
|
+
| ------------------------ | -------------------------- | ---------------------------- | ------------------------------------------------ |
|
|
437
|
+
| `action` | `--action` | `LDB_ACTION` | `config[.<PROFILE>].yml: action` |
|
|
438
|
+
| `mode` | `--mode` | `LDB_MODE` | `config[.<PROFILE>].yml: mode` |
|
|
439
|
+
| `chunk_size` | `--chunk-size` | `LDB_CHUNK_SIZE` | `config[.<PROFILE>].yml: chunk_size` |
|
|
440
|
+
| `use_added_columns` | — | — | `config[.<PROFILE>].yml: use_added_columns` |
|
|
441
|
+
| `add_ldb_columns` | — | — | `config[.<PROFILE>].yml: add_ldb_columns` |
|
|
442
|
+
| `parallel_max` | `--parallel-max` | `LDB_PARALLEL_MAX` | `config[.<PROFILE>].yml: parallel_max` |
|
|
443
|
+
| `db_engine` | `--db-engine` | `LDB_DB_ENGINE` | `config[.<PROFILE>].yml: db_engine` |
|
|
444
|
+
| `log_level` | `--log-level` | `LDB_LOG_LEVEL` | `config[.<PROFILE>].yml: log_level` |
|
|
445
|
+
| `schema` | `--schema` | `LDB_SCHEMA` | CLI only (not stored). |
|
|
446
|
+
| `profile` | `--profile` | `LDB_PROFILE` | CLI only (not stored). |
|
|
447
|
+
| `ilm_config_file` | `--ilm-config-file` | `LDB_ILM_CONFIG_FILE` | CLI only (not stored). |
|
|
448
|
+
| `source_dsn` | `--source-dsn` | `LDB_SOURCE_DSN` | `config[.<PROFILE>].yml: source_dsn` |
|
|
449
|
+
| `source_username` | `--source-username` | `LDB_SOURCE_USERNAME` | `config[.<PROFILE>].yml: source_username` |
|
|
450
|
+
| `source_password` | — | — | `secrets[.<PROFILE>].json: source_password` |
|
|
451
|
+
| `history_dsn` | `--history-dsn` | `LDB_HISTORY_DSN` | `config[.<PROFILE>].yml: history_dsn` |
|
|
452
|
+
| `history_username` | `--history-username` | `LDB_HISTORY_USERNAME` | `config[.<PROFILE>].yml: history_username` |
|
|
453
|
+
| `history_password` | — | — | `secrets[.<PROFILE>].json: history_password` |
|
|
454
|
+
| `admin_source_username` | `--admin-source-username` | `LDB_ADMIN_SOURCE_USERNAME` | `config[.<PROFILE>].yml: admin_source_username` |
|
|
455
|
+
| `admin_source_password` | — | — | `secrets[.<PROFILE>].json: admin_source_password` |
|
|
456
|
+
| `admin_history_username` | `--admin-history-username` | `LDB_ADMIN_HISTORY_USERNAME` | `config[.<PROFILE>].yml: admin_history_username` |
|
|
457
|
+
| `admin_history_password` | — | — | `secrets[.<PROFILE>].json: admin_history_password` |
|
|
458
|
+
|
|
459
|
+
Builder-only flags (`--config-dir`, `--config-file`, `--set`) control how overlays are discovered and have no equivalent entry in the configuration files.
|
|
460
|
+
|
|
461
|
+
## ILM Rule Semantics
|
|
462
|
+
|
|
463
|
+
Each entry in `ilm[.<PROFILE>].yml` merges table-level attributes with one or more rule conditions defined under `conds`. When `conds` is omitted, LimitsDb assumes a single active rule so the table remains eligible for processing.
|
|
464
|
+
|
|
465
|
+
- **Activation:** A condition runs only when `is_active: true`. Deactivating the sole condition for a table effectively removes that table from the run.
|
|
466
|
+
- **Retention windows:** `retain_months_source` is required whenever `purge_date_expr` is present. `retain_months_history` extends the history window but also depends on defining the source retention. During `HISTORY_ILM` runs, the engine sums source and history months to determine the cut-off date.
|
|
467
|
+
- **Date expressions:** `purge_date_expr` identifies the date column (or expression) that anchors retention. Prefix column references with `@` (for example, `"@DSP_DATE"`); the runner swaps the prefix for the proper table alias at execution time.
|
|
468
|
+
- **Additional filters:** Add optional filters through `additional_filter_expr` (source runs) and `history_addtl_filter_expr` (history runs). Both accept the same `@column` syntax, and the history expression falls back to the source expression when omitted.
|
|
469
|
+
- **Referencing tables:** Use `referencing_tables` to pull parent conditions into child tables. List entries as `<TABLE> <ALIAS>` (optionally `<OWNER>.<TABLE> <ALIAS>`) and supply matching `join_expr` fragments. The runner inherits active conditions from each referenced table and rewrites the join fragments—`@` becomes `inner` joins by default or `left outer` joins when `source_orphan_purge: true` to find orphans.
|
|
470
|
+
- **Historical predicate snapshot:** With `use_added_columns` enabled, every archived row preserves the values needed to reevaluate all its predicates in history, including values sourced from related tables. Distinct cut-off dates are stored in helper columns such as `ldb_date_<suffix>`. Predicates that share a date reuse the same helper column while retaining their own filters and retention windows. Other values sourced from related tables are materialized as `<column>_<table_alias>`.
|
|
471
|
+
- **Orphan handling:** Enable `source_orphan_purge` with `orphan_check_column` to archive source rows whose referenced parent is absent. The source query uses `left outer` joins and treats the row as an orphan when any comma-separated check column is `NULL`. `referencing_tables`, `join_expr`, `orphan_check_column`, `use_added_columns: true`, and a positive historical retention are required. Orphans follow the table's normal source-to-history flow rather than being deleted directly. LimitsDb snapshots this state in `LDB_IS_ORPHAN` and stores a fallback date so `HISTORY_ILM` can apply the configured retention without accessing the missing parent.
|
|
472
|
+
|
|
473
|
+
## Configuration Resolution (Overlay Order)
|
|
474
|
+
|
|
475
|
+
Lowest → highest priority:
|
|
476
|
+
|
|
477
|
+
1. System root: `/etc/limitsdb`
|
|
478
|
+
2. User root: `~/.config/LimitsDb`
|
|
479
|
+
3. `--config-file` (extra overlay)
|
|
480
|
+
4. Registered environment variables (`Env("LDB_*")` metadata)
|
|
481
|
+
5. `--<param> value` or `--set key=value`
|
|
482
|
+
|
|
483
|
+
After overlays, secrets from `secrets[.<PROFILE>].json` are loaded and decrypted. If any secret is plaintext and enforcement is enabled (default), the loader raises an error.
|
|
484
|
+
|
|
485
|
+
Tip: you can redirect both “system” and “user” roots to the same place with `--config-dir`.
|
|
486
|
+
|
|
487
|
+
## Configuration Files
|
|
488
|
+
|
|
489
|
+
### `config[.<PROFILE>].yml` (commented defaults + help)
|
|
490
|
+
|
|
491
|
+
Every key is commented; the default value and short help appear inline. Example:
|
|
492
|
+
|
|
493
|
+
```yaml
|
|
494
|
+
# action: "SOURCE_ILM" # ILM target: months_keep_history_max (SOURCE_ILM) or history (HISTORY_ILM)
|
|
495
|
+
# mode: "PREVIEW" # VALIDATE | PLAN | PREVIEW | SCRIPT | EXECUTE (PREVIEW mirrors legacy DRY_RUN)
|
|
496
|
+
# chunk_size: 100000 # Rows per chunk when processing large tables
|
|
497
|
+
# use_added_columns: True # Populate derived columns in history tables
|
|
498
|
+
# add_ldb_columns: True # Add LimitsDb execution-date columns in history tables
|
|
499
|
+
# parallel_max: 10 # Maximum number of parallel processes
|
|
500
|
+
# db_engine: "oracle" # Database engine
|
|
501
|
+
# log_level: "INFO" # Logging level
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
`oracle` is the only supported `db_engine`. PostgreSQL remains a future implementation; any other value is rejected.
|
|
505
|
+
|
|
506
|
+
Uncomment and set values as needed. Secrets are not listed here (they live in `secrets[.<PROFILE>].json`).
|
|
507
|
+
|
|
508
|
+
### `ilm[.<PROFILE>].yml`
|
|
509
|
+
|
|
510
|
+
Empty list scaffolded by `ldb-init`. You define your ILM tables here.
|
|
511
|
+
|
|
512
|
+
### `ilm[.<PROFILE>].example.yml`
|
|
513
|
+
|
|
514
|
+
Comprehensive, commented example shipped in the package and copied verbatim by `ldb-init`.
|
|
515
|
+
|
|
516
|
+
### `secrets[.<PROFILE>].json`
|
|
517
|
+
|
|
518
|
+
Holds only secret fields (empty by default). Must be encrypted (run `ldb-crypt`) before the main runner will accept them.
|
|
519
|
+
|
|
520
|
+
## Environment Variables
|
|
521
|
+
|
|
522
|
+
Only the variables listed in the table above work as overrides; any other `LDB_*` variable is ignored. Examples:
|
|
523
|
+
|
|
524
|
+
- `LDB_PARALLEL_MAX=8` → `parallel_max: 8`
|
|
525
|
+
- `LDB_LOG_LEVEL=DEBUG` → `log_level: "DEBUG"`
|
|
526
|
+
|
|
527
|
+
Booleans accept `true/false`, `1/0`, `on/off` (case-insensitive).
|
|
528
|
+
|
|
529
|
+
`use_added_columns` and `add_ldb_columns` are intentionally file-only because changing the historical table shape
|
|
530
|
+
between runs can destabilize history processing. They cannot be overridden through environment variables or `--set`.
|
|
531
|
+
|
|
532
|
+
## Troubleshooting
|
|
533
|
+
|
|
534
|
+
- Plaintext secret detected
|
|
535
|
+
Run `ldb-crypt --schema <SCHEMA> [--profile <PROFILE>]`. Or set the value to `""` until you’re ready.
|
|
536
|
+
|
|
537
|
+
- Oracle thick mode required
|
|
538
|
+
Install Oracle Instant Client and configure library paths (`PATH` on Windows, `LD_LIBRARY_PATH` on Linux/macOS).
|
|
539
|
+
|
|
540
|
+
- Configuration not found
|
|
541
|
+
Use `ldb-init` to scaffold files or pass `--config-dir` to point at the correct root.
|
|
542
|
+
|
|
543
|
+
- Unexpected key in config
|
|
544
|
+
The loader is strict—unknown keys raise an error. Fix typos or remove unused entries.
|
|
545
|
+
|
|
546
|
+
- Invalid or unreadable secrets file
|
|
547
|
+
LimitsDb stops before database work and leaves the file unchanged. Repair the JSON or key, then rerun `ldb-crypt`.
|
|
548
|
+
|
|
549
|
+
Low-level configuration, secret, connection, validation, and execution failures are exposed as domain errors while
|
|
550
|
+
preserving their original cause. See [exception handling](docs/exception-handling.md) for the boundary contract and
|
|
551
|
+
broad-catch inventory.
|
|
552
|
+
|
|
553
|
+
## License
|
|
554
|
+
|
|
555
|
+
LimitsDb is released under the **Apache License 2.0**.
|
|
556
|
+
You are free to use, modify, and redistribute the software — including for commercial purposes — provided that you comply with the terms of that license.
|
|
557
|
+
|
|
558
|
+
All open-source source code of LimitsDb remains free and community-driven.
|
|
559
|
+
However, **Inversiones Etimo SpA** retains the exclusive right to produce, brand, and distribute proprietary or commercial editions of LimitsDb that may include additional features, services, or licensing terms.
|
|
560
|
+
|
|
561
|
+
📄 See [LICENSE](LICENSE), [LICENSE-DUAL.md](LICENSE-DUAL.md), and [NOTICE](NOTICE) for details.
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## Governance and Ownership
|
|
566
|
+
|
|
567
|
+
LimitsDb is maintained by **Inversiones Etimo SpA**
|
|
568
|
+
📧 contacto@etimo.cl
|
|
569
|
+
🌐 [https://www.etimo.cl](https://www.etimo.cl)
|
|
570
|
+
|
|
571
|
+
### Project Governance
|
|
572
|
+
|
|
573
|
+
- **Maintainer:** Inversiones Etimo SpA (core architecture, releases, roadmap).
|
|
574
|
+
- **Community contributions:** welcomed via pull requests under the [CONTRIBUTING.md](CONTRIBUTING.md) guidelines.
|
|
575
|
+
- **Issue tracking & discussions:** handled publicly through GitHub Issues and Discussions.
|
|
576
|
+
- **Release model:**
|
|
577
|
+
- `development` → integration branch for new work.
|
|
578
|
+
- `main` → stable, production-ready releases.
|
|
579
|
+
- Periodic tags and changelogs define official versions.
|
|
580
|
+
|
|
581
|
+
### Ownership
|
|
582
|
+
|
|
583
|
+
All intellectual property and trademarks for LimitsDb are owned by **Inversiones Etimo SpA**.
|
|
584
|
+
Open-source distribution under the Apache 2.0 license does **not** transfer ownership of the software or brand.
|
|
585
|
+
Any proprietary extensions, hosted services, or commercial editions may be offered solely by Inversiones Etimo SpA.
|
|
586
|
+
|