strata-cli 0.1.3.beta → 0.1.4.beta

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0dc0377469e1bfb8d12c50f839b1f530d2104b1b894e5623d0f009081e60f1e5
4
- data.tar.gz: f4595f187e23891e5b1d64ef384ae48b1d3e73bd34a5ab8afefab9886b95f5ad
3
+ metadata.gz: 2ea80c6d9e3c9d9db1f592e8fc07470b23fecafe6a31052aecd69b948f1bdec7
4
+ data.tar.gz: 57af64d1411a970716f5be79db6ac93b9c54b4f76c0f0dd1265a372ff1c28607
5
5
  SHA512:
6
- metadata.gz: b13368ec18b1d53316d3eb01f42f869ff81e8297b2f5451c337073cf0fed8400694a629136c3bbc8bec9b3bfd1affd786a9b1343a4b9b6f3561089d5aba86e9c
7
- data.tar.gz: c47cfbdd8e1d54dda6b9b92b3e6385bf14f8d0e03c608721436dafeb70177fe2f51893003721edd1bebb757bbd8f0eefc3164c6c9287707ffc8ee3f86d2175f1
6
+ metadata.gz: b4de4eb2ce818ce0fe851b79f3fe0d82b2540257246638052c034506d605256bd98ca3cbe7a61dac0e4b240258f39bd6b4cadfeb3681a59038851d2257e68266
7
+ data.tar.gz: 9db418cf2a36236856cafda813885684ad3e9a558ab4bd44ce60f52d57a202f77124b69270b044fd940ef58d95db3f6edfdb9ca36efbaa078e073bc20f6cb68a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.4.beta] - 2026-02-26
4
+
5
+ ### Added
6
+
7
+ - **Table generator**: Support synonyms for fields in generated tables.
8
+
9
+ ### Changed
10
+
11
+ - **Server configuration**: Refactored server config handling and improved `project.yml` persistence.
12
+ - **Datasource helper**: Read-only mode support for file-based databases.
13
+
3
14
  ## [0.1.3.beta] - 2026-01-28
4
15
 
5
16
  ### Added
data/README.md CHANGED
@@ -440,8 +440,9 @@ Release a new version:
440
440
 
441
441
  1. Update version in `lib/strata/cli/version.rb`
442
442
  2. Update `CHANGELOG.md` with the new version and changes
443
- 3. Commit the changes: `git add lib/strata/cli/version.rb CHANGELOG.md && git commit -m "Bump version to X.Y.Z"`
444
- 4. Run `bundle exec rake release` (builds gem, creates git tag, and pushes to rubygems.org)
443
+ 3. Commit and merge to `master`: `git add lib/strata/cli/version.rb CHANGELOG.md && git commit -m "Bump version to X.Y.Z"` (then open a PR and merge)
444
+ 4. **Via GitHub Actions (recommended):** In the repo go to **Actions → Release → Run workflow**, choose the branch (e.g. `master`), optionally enable "Build and test only" for a dry run, then **Run workflow**. Ensure the repo secret `RUBYGEMS_API_KEY` is set (RubyGems API key with push permission).
445
+ 5. **Via console:** From a checkout of `master` after the version-bump merge, run `bundle exec rake release` (builds gem, creates git tag, pushes tag and gem to RubyGems).
445
446
 
446
447
  ## Contributing
447
448
 
@@ -20,6 +20,9 @@ module Strata
20
20
  - schema_type: "dimension" for categorical/text, "measure" for numeric aggregations
21
21
  - data_type: string, integer, bigint, decimal, date, date_time, boolean
22
22
  - expression: SQL expression (for measures include aggregation like "sum(amount)")
23
+ - synonyms: Array of 2-4 alternative names users might use to refer to this field.
24
+ These help AI search and natural language queries find the right field.
25
+ Example: "Customer ID" → ["cust id", "client id", "buyer id"]
23
26
 
24
27
  Output ONLY valid JSON array, no explanations.
25
28
  PROMPT
@@ -120,8 +123,8 @@ module Strata
120
123
 
121
124
  #{column_list}#{context_section}#{user_context_section}
122
125
 
123
- Return JSON array with objects containing: name, description, schema_type, data_type, expression
124
- Example: [{"name": "Order ID", "description": "Primary key", "schema_type": "dimension", "data_type": "bigint", "expression": "id"}]
126
+ Return JSON array with objects containing: name, description, schema_type, data_type, expression, synonyms
127
+ Example: [{"name": "Order ID", "description": "Primary key", "schema_type": "dimension", "data_type": "bigint", "expression": "id", "synonyms": ["order number", "order key"]}]
125
128
  PROMPT
126
129
  end
127
130
 
@@ -153,7 +156,7 @@ module Strata
153
156
  #{column_list}#{context_section}
154
157
 
155
158
  Based on the user's request, regenerate or modify the field definitions.
156
- Return JSON array with objects containing: name, description, schema_type, data_type, expression
159
+ Return JSON array with objects containing: name, description, schema_type, data_type, expression, synonyms
157
160
  PROMPT
158
161
  end
159
162
 
@@ -207,7 +210,8 @@ module Strata
207
210
  description: "",
208
211
  schema_type: is_measure ? "measure" : "dimension",
209
212
  data_type: map_data_type(type),
210
- expression: is_measure ? "sum(#{name})" : name
213
+ expression: is_measure ? "sum(#{name})" : name,
214
+ synonyms: []
211
215
  }
212
216
  end
213
217
  end
@@ -6,10 +6,9 @@ module Strata
6
6
  STRATA_CONFIG_FILE = ".strata"
7
7
  PROJECT_CONFIG_FILE = "project.yml"
8
8
 
9
- # Default configuration
10
9
  DEFAULT = {
11
10
  "api_key" => "",
12
- "server" => "http://localhost:3030",
11
+ "server" => "",
13
12
  "log_level" => "info"
14
13
  }.freeze
15
14
 
@@ -108,6 +108,11 @@ module Strata
108
108
  "data_type" => normalized[:data_type]
109
109
  }
110
110
 
111
+ synonyms = normalized[:synonyms]
112
+ if synonyms.is_a?(Array) && !synonyms.empty?
113
+ field_hash["synonyms"] = synonyms
114
+ end
115
+
111
116
  # Build expression with proper nested format
112
117
  expr = normalized[:expression]
113
118
  field_hash["expression"] = {
@@ -96,6 +96,12 @@ fields:
96
96
  # array: true|false (optional)
97
97
  # sql: my_field_column (Required)
98
98
  #
99
+ # # Optional: Alternative names for this field. Helps AI and search
100
+ # # find this field when users refer to it by different names.
101
+ # synonyms:
102
+ # - alt name one
103
+ # - alt name two
104
+ #
99
105
  # # Optional: Exclude certain dimnesions from the group by/filter
100
106
  # exclusion_type: exclude|exclude_all_except|exclude_all
101
107
  # exclusions: # (Required when exclusion type is set and isnt exclude_all)
@@ -42,9 +42,26 @@ module Strata
42
42
  config = ds_config(ds_key).merge(Credentials.fetch(ds_key))
43
43
  adapter_sym = config["adapter"].to_sym
44
44
  ensure_adapter_driver_gems!(adapter_sym)
45
+
46
+ # CLI only performs read operations (test, tables, metadata).
47
+ # Use read-only mode for file-based databases to avoid lock conflicts.
48
+ apply_readonly_mode(adapter_sym, config)
49
+
45
50
  DWH.create(adapter_sym, config)
46
51
  end
47
52
 
53
+ def apply_readonly_mode(adapter_sym, config)
54
+ case adapter_sym
55
+ when :duckdb
56
+ config["duck_config"] ||= {}
57
+ config["duck_config"]["access_mode"] = "READ_ONLY"
58
+ when :sqlite
59
+ config["readonly"] = true
60
+ end
61
+ # Client-server databases (postgres, mysql, snowflake, etc.)
62
+ # don't need special handling - no file lock issues
63
+ end
64
+
48
65
  def ensure_adapter_driver_gems!(adapter_sym)
49
66
  required = ADAPTER_DRIVER_GEMS.fetch(adapter_sym, [])
50
67
  return if required.empty?
@@ -46,6 +46,34 @@ module Strata
46
46
  end
47
47
  end
48
48
 
49
+ # Persists server URL to project.yml (updates existing or appends)
50
+ def persist_server_to_project_yml(server, project_yml_path: "project.yml")
51
+ return false unless server && !server.to_s.strip.empty?
52
+ return false unless File.exist?(project_yml_path)
53
+
54
+ project_yml_content = File.read(project_yml_path)
55
+
56
+ begin
57
+ if /^server:\s*.+$/m.match?(project_yml_content)
58
+ updated_content = project_yml_content.gsub(/^(\s*)server:\s*.+$/, "\\1server: #{server}")
59
+ File.write(project_yml_path, updated_content)
60
+ else
61
+ File.open(project_yml_path, "a") do |f|
62
+ f.puts "\n" unless project_yml_content.end_with?("\n")
63
+ f.puts "server: #{server}"
64
+ end
65
+ end
66
+
67
+ true
68
+ rescue Errno::EACCES => e
69
+ raise Strata::CommandError, "Permission denied writing to #{project_yml_path}: #{e.message}"
70
+ rescue Errno::ENOSPC => e
71
+ raise Strata::CommandError, "Disk full: #{e.message}"
72
+ rescue => e
73
+ raise Strata::CommandError, "Failed to write to #{project_yml_path}: #{e.message}"
74
+ end
75
+ end
76
+
49
77
  # Persists git URL to project.yml file if missing
50
78
  def persist_git_url_if_missing(project_yml_path: "project.yml")
51
79
  return false unless File.exist?(project_yml_path)
@@ -1,6 +1,7 @@
1
1
  require_relative "../guard"
2
2
  require_relative "../credentials"
3
3
  require_relative "../terminal"
4
+ require_relative "../utils/git"
4
5
  require "tty-prompt"
5
6
  require_relative "../helpers/datasource_helper"
6
7
  require_relative "../helpers/description_helper"
@@ -369,6 +370,8 @@ module Strata
369
370
  strata_file = Configuration::STRATA_CONFIG_FILE
370
371
  File.chmod(0o600, strata_file) if File.exist?(strata_file)
371
372
 
373
+ Utils::Git.commit_file(Configuration::STRATA_CONFIG_FILE, "[Strata-CLI] Add AI config to .strata", Dir.pwd) if Utils::Git.git_repo?
374
+
372
375
  say "\n✔ AI configured with #{provider}", :green
373
376
  say " Note: API key is stored securely in .strata (not committed to repo)", :cyan
374
377
  end
@@ -122,7 +122,7 @@ module Strata
122
122
 
123
123
  def validate_deployment_configuration(config)
124
124
  ensure_api_key(config)
125
- validate_server_url(config)
125
+ ensure_server(config)
126
126
  ensure_git_url_populated
127
127
  ensure_project_id(config)
128
128
  end
@@ -133,14 +133,36 @@ module Strata
133
133
  config["api_key"] = collect_api_key_interactively
134
134
  end
135
135
 
136
- def validate_server_url(config)
137
- server_url = config["server"]
138
- return if server_url && !server_url.to_s.strip.empty?
136
+ def ensure_server(config)
137
+ return if config["server"] && !config["server"].to_s.strip.empty?
139
138
 
140
- env_msg = options[:environment] ? " (or in '#{options[:environment]}' environment section)" : ""
141
- say "\nServer URL not configured in project.yml#{env_msg}", :yellow
142
- say "Please add or update the 'server' field in project.yml and try again.\n", :white
143
- exit(1)
139
+ config["server"] = collect_server_interactively
140
+ end
141
+
142
+ def collect_server_interactively
143
+ prompt = TTY::Prompt.new
144
+
145
+ say "\nServer URL not found (not in project.yml)", :yellow
146
+ say "You can add it to project.yml or enter it now here\n", :cyan
147
+
148
+ server = prompt.ask("Enter Strata server URL:") do |q|
149
+ q.required true
150
+ q.validate(/\S+/, "Server URL cannot be empty")
151
+ end
152
+
153
+ server = server.strip.sub(%r{/\z}, "") # normalize: remove trailing slash
154
+
155
+ with_spinner("Saving server URL to project.yml") do
156
+ save_server_to_project_yml(server)
157
+ end
158
+
159
+ server
160
+ end
161
+
162
+ def save_server_to_project_yml(server)
163
+ Helpers::ProjectHelper.persist_server_to_project_yml(server, project_yml_path: File.join(project_path, Configuration::PROJECT_CONFIG_FILE))
164
+ CLI.config.reload!
165
+ Utils::Git.commit_file(Configuration::PROJECT_CONFIG_FILE, "[Strata-CLI] Add server URL to project.yml", project_path) if Utils::Git.git_repo?
144
166
  end
145
167
 
146
168
  def ensure_git_url_populated
@@ -182,37 +204,43 @@ module Strata
182
204
  save_api_key_to_strata(api_key)
183
205
  end
184
206
 
207
+ Utils::Git.commit_file(Configuration::STRATA_CONFIG_FILE, "[Strata-CLI] Save API key to .strata", project_path) if Utils::Git.git_repo?
208
+
185
209
  api_key
186
210
  end
187
211
 
188
212
  def save_api_key_to_strata(api_key)
213
+ save_key_to_strata("api_key", api_key)
214
+ end
215
+
216
+ def save_key_to_strata(key, value)
189
217
  strata_file = Configuration::STRATA_CONFIG_FILE
190
218
 
191
219
  # Read existing content if file exists
192
220
  existing_content = File.exist?(strata_file) ? File.read(strata_file) : ""
193
221
 
194
222
  begin
195
- if /^api_key:\s*.+$/m.match?(existing_content)
196
- updated_content = existing_content.gsub(/^(\s*)api_key:\s*.+$/, "\\1api_key: #{api_key}")
223
+ if /^#{Regexp.escape(key)}:\s*.+$/m.match?(existing_content)
224
+ updated_content = existing_content.gsub(/^(\s*)#{Regexp.escape(key)}:\s*.+$/, "\\1#{key}: #{value}")
197
225
  File.write(strata_file, updated_content)
198
226
  else
199
227
  File.open(strata_file, "a") do |f|
200
228
  f.puts "\n" unless existing_content.empty? || existing_content.end_with?("\n")
201
- f.puts "api_key: #{api_key}"
229
+ f.puts "#{key}: #{value}"
202
230
  end
203
231
  end
204
232
 
205
233
  # Set restrictive permissions (read/write for owner only)
206
234
  File.chmod(0o600, strata_file) if File.exist?(strata_file)
207
235
 
208
- # Reload config to pick up the new API key
236
+ # Reload config to pick up the new value
209
237
  CLI.config.reload!
210
238
  rescue Errno::EACCES => e
211
239
  raise Strata::CommandError, "Permission denied writing to #{strata_file}: #{e.message}"
212
240
  rescue Errno::ENOSPC => e
213
241
  raise Strata::CommandError, "Disk full: #{e.message}"
214
242
  rescue => e
215
- raise Strata::CommandError, "Failed to write API key to #{strata_file}: #{e.message}"
243
+ raise Strata::CommandError, "Failed to write #{key} to #{strata_file}: #{e.message}"
216
244
  end
217
245
  end
218
246
 
@@ -405,6 +433,7 @@ module Strata
405
433
  with_spinner("Persisting project ID to project.yml") do
406
434
  Helpers::ProjectHelper.persist_project_id_to_yml(project_id)
407
435
  end
436
+ Utils::Git.commit_file(Configuration::PROJECT_CONFIG_FILE, "[Strata-CLI] Persist project ID to project.yml", project_path) if Utils::Git.git_repo?
408
437
  end
409
438
 
410
439
  def refresh_external_imports
@@ -143,6 +143,10 @@ module Strata
143
143
  return if field[:expression] == "back"
144
144
 
145
145
  field[:schema_type] = prompt.select(" Type:", %w[dimension measure], default: field[:schema_type])
146
+
147
+ current_synonyms = (field[:synonyms] || []).join(", ")
148
+ synonyms_input = prompt.ask(" Synonyms (comma-separated):", default: current_synonyms)
149
+ field[:synonyms] = synonyms_input.to_s.split(",").map(&:strip).reject(&:empty?)
146
150
  rescue TTY::Reader::InputInterrupt
147
151
  # User pressed Ctrl+C, go back without saving
148
152
  nil
@@ -127,7 +127,7 @@ module Strata
127
127
  rescue Interrupt
128
128
  stop_all_spinners
129
129
  say "\n\n Monitoring interrupted. Deployment continues in background.", ColorHelper.warning
130
- say " Check server for deployment status.\n", ColorHelper.info
130
+ say " Check server for deployment status with command `strata deploy status`.\n", ColorHelper.info
131
131
  nil
132
132
  rescue => e
133
133
  stop_all_spinners
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Strata
4
4
  module CLI
5
- VERSION = "0.1.3.beta"
5
+ VERSION = "0.1.4.beta"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strata-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3.beta
4
+ version: 0.1.4.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ajo Abraham
@@ -330,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
330
330
  - !ruby/object:Gem::Version
331
331
  version: '0'
332
332
  requirements: []
333
- rubygems_version: 3.6.9
333
+ rubygems_version: 3.6.7
334
334
  specification_version: 4
335
335
  summary: Command-line interface for the Strata Semantic Analytics System
336
336
  test_files: []