rails-nl2sql 0.1.8 → 0.2.0
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 +4 -4
- data/.DS_Store +0 -0
- data/README.md +22 -0
- data/lib/generators/rails_nl2sql/install/install_generator.rb +13 -0
- data/lib/generators/rails_nl2sql/install/templates/rails_nl2sql.rb +4 -0
- data/lib/rails/nl2sql/active_record_extension.rb +21 -0
- data/lib/rails/nl2sql/query_generator.rb +9 -4
- data/lib/rails/nl2sql/query_validator.rb +8 -1
- data/lib/rails/nl2sql/schema_builder.rb +14 -1
- data/lib/rails/nl2sql/version.rb +1 -1
- data/lib/rails/nl2sql.rb +6 -0
- data/lib/rails-nl2sql.rb +2 -0
- data/rails-nl2sql.gemspec +1 -1
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c82ac012038c7065a0c3eeb3db0389fb64eec1fe6c95ae4c0896d6c580527dcc
|
4
|
+
data.tar.gz: 2a6236aad4a76959d360f6b19a7c7c38f662e66cfa7799108a4dd4e6cc546a7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abe39e44ac4a2443b3cb778f7393cc012099c9266e1a35d25b3ad3bfdfae0b43b27a1206f52026f7cd31342931dc35ec0012ceb3bb8245a23fdadbaa9112da17
|
7
|
+
data.tar.gz: 0ab5536299aa7f4b7063c4c5264ec1b335a7e34957537c18da0bfa19d86b991efc135288d70be76938858e25ad9219d6f4f4d0b0299b72af212a7cb68ffa9418
|
data/.DS_Store
ADDED
Binary file
|
data/README.md
CHANGED
@@ -42,6 +42,16 @@ To execute a natural language query, you can use the `execute` method:
|
|
42
42
|
results = Rails::Nl2sql::Processor.execute("Show me all the users from California")
|
43
43
|
```
|
44
44
|
|
45
|
+
### Using `from_nl` with ActiveRecord
|
46
|
+
|
47
|
+
You can call the NL2SQL processor directly on your models. The `from_nl` method
|
48
|
+
returns an `ActiveRecord::Relation` so you can chain scopes, pagination and
|
49
|
+
other query modifiers as usual.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
User.from_nl("all users who signed up last week").limit(10)
|
53
|
+
```
|
54
|
+
|
45
55
|
You can also specify which tables to include or exclude:
|
46
56
|
|
47
57
|
```ruby
|
@@ -60,6 +70,18 @@ Rails::Nl2sql::Processor.get_tables
|
|
60
70
|
Rails::Nl2sql::Processor.get_schema(include: ["users", "orders"])
|
61
71
|
```
|
62
72
|
|
73
|
+
### Schema caching
|
74
|
+
|
75
|
+
For efficiency the gem caches the full database schema on first use. The cached
|
76
|
+
schema is reused for subsequent requests so your application doesn't need to hit
|
77
|
+
the database every time a prompt is generated.
|
78
|
+
|
79
|
+
You can clear the cached schema if your database changes:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Rails::Nl2sql::SchemaBuilder.clear_cache!
|
83
|
+
```
|
84
|
+
|
63
85
|
## Development
|
64
86
|
|
65
87
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module RailsNl2sql
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
|
8
|
+
def copy_initializer
|
9
|
+
template 'rails_nl2sql.rb', 'config/initializers/rails_nl2sql.rb'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/lazy_load_hooks'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Nl2sql
|
6
|
+
module ActiveRecordExtension
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def from_nl(prompt, options = {})
|
11
|
+
sql = Rails::Nl2sql::Processor.generate_query_only(prompt, options)
|
12
|
+
from(Arel.sql("(#{sql}) AS #{table_name}"))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveSupport.on_load(:active_record) do
|
20
|
+
include Rails::Nl2sql::ActiveRecordExtension
|
21
|
+
end
|
@@ -11,6 +11,11 @@ module Rails
|
|
11
11
|
def generate_query(prompt, schema, db_server = "PostgreSQL", tables = nil)
|
12
12
|
retrieved_context = build_context(schema, tables)
|
13
13
|
|
14
|
+
# Debug: Let's see what schema context is being sent
|
15
|
+
puts "=== SCHEMA CONTEXT BEING SENT TO AI ==="
|
16
|
+
puts retrieved_context
|
17
|
+
puts "=== END SCHEMA CONTEXT ==="
|
18
|
+
|
14
19
|
system_prompt = build_system_prompt(db_server, retrieved_context)
|
15
20
|
user_prompt = build_user_prompt(prompt)
|
16
21
|
|
@@ -20,7 +25,7 @@ module Rails
|
|
20
25
|
parameters: {
|
21
26
|
model: @model,
|
22
27
|
prompt: full_prompt,
|
23
|
-
max_tokens:
|
28
|
+
max_tokens: 500,
|
24
29
|
temperature: 0.1
|
25
30
|
}
|
26
31
|
)
|
@@ -83,9 +88,9 @@ module Rails
|
|
83
88
|
---
|
84
89
|
**SQL GENERATION RULES:**
|
85
90
|
1. **SQL Dialect:** All generated SQL must be valid **#{db_server} syntax**.
|
86
|
-
* For limiting results, use
|
87
|
-
* Be mindful of #{db_server}'s specific function names (e.g.,
|
88
|
-
* For subqueries that return a single value to be used in a
|
91
|
+
* For limiting results, use LIMIT (e.g., LIMIT 10) instead of TOP.
|
92
|
+
* Be mindful of #{db_server}'s specific function names (e.g., COUNT(*), MAX()) and behaviors.
|
93
|
+
* For subqueries that return a single value to be used in a WHERE clause, ensure they are correctly formatted for #{db_server}.
|
89
94
|
2. **Schema Adherence:** Only use table names and column names that are explicitly present in the provided context. Do not invent names.
|
90
95
|
3. **Valid JOIN Paths:** All `JOIN` operations must be based on valid foreign key relationships. The provided schema context explicitly details many of these.
|
91
96
|
4. **Safety First:** Absolutely **DO NOT** generate any DDL (CREATE, ALTER, DROP) or DML (INSERT, UPDATE, DELETE) statements. Only `SELECT` queries are permitted.
|
@@ -15,11 +15,18 @@ module Rails
|
|
15
15
|
# Basic validation: prevent destructive commands
|
16
16
|
disallowed_keywords = %w(DROP DELETE UPDATE INSERT TRUNCATE ALTER CREATE EXEC EXECUTE MERGE REPLACE)
|
17
17
|
query_upper = query.upcase
|
18
|
-
|
18
|
+
|
19
19
|
if disallowed_keywords.any? { |keyword| query_upper.include?(keyword) }
|
20
20
|
raise Rails::Nl2sql::Error, "Query contains disallowed keywords."
|
21
21
|
end
|
22
22
|
|
23
|
+
# Ensure there is only a single statement
|
24
|
+
cleaned_query = query.rstrip
|
25
|
+
cleaned_query = cleaned_query.chomp(';')
|
26
|
+
if cleaned_query.include?(';')
|
27
|
+
raise Rails::Nl2sql::Error, "Query contains multiple statements."
|
28
|
+
end
|
29
|
+
|
23
30
|
# Ensure it's a SELECT query
|
24
31
|
unless query_upper.strip.start_with?('SELECT', 'WITH')
|
25
32
|
raise Rails::Nl2sql::Error, "Only SELECT queries are allowed."
|
@@ -1,13 +1,26 @@
|
|
1
1
|
module Rails
|
2
2
|
module Nl2sql
|
3
3
|
class SchemaBuilder
|
4
|
+
@@schema_cache = nil
|
5
|
+
|
4
6
|
def self.build_schema(options = {})
|
7
|
+
if options.empty? && @@schema_cache
|
8
|
+
return @@schema_cache
|
9
|
+
end
|
10
|
+
|
5
11
|
tables = get_filtered_tables(options)
|
6
|
-
|
12
|
+
|
7
13
|
schema_text = build_schema_text(tables)
|
14
|
+
|
15
|
+
@@schema_cache = schema_text if options.empty?
|
16
|
+
|
8
17
|
schema_text
|
9
18
|
end
|
10
19
|
|
20
|
+
def self.clear_cache!
|
21
|
+
@@schema_cache = nil
|
22
|
+
end
|
23
|
+
|
11
24
|
def self.get_database_type
|
12
25
|
adapter = ActiveRecord::Base.connection.adapter_name.downcase
|
13
26
|
case adapter
|
data/lib/rails/nl2sql/version.rb
CHANGED
data/lib/rails/nl2sql.rb
CHANGED
@@ -2,6 +2,7 @@ require "rails/nl2sql/version"
|
|
2
2
|
require "rails/nl2sql/query_generator"
|
3
3
|
require "rails/nl2sql/schema_builder"
|
4
4
|
require "rails/nl2sql/query_validator"
|
5
|
+
require "rails/nl2sql/active_record_extension"
|
5
6
|
require "rails/nl2sql/railtie" if defined?(Rails)
|
6
7
|
|
7
8
|
module Rails
|
@@ -26,6 +27,11 @@ module Rails
|
|
26
27
|
# Build schema with optional table filtering
|
27
28
|
schema = SchemaBuilder.build_schema(options)
|
28
29
|
|
30
|
+
# Debug: Show what schema is being built
|
31
|
+
puts "=== RAW SCHEMA FROM BUILDER ==="
|
32
|
+
puts schema
|
33
|
+
puts "=== END RAW SCHEMA ==="
|
34
|
+
|
29
35
|
# Extract tables for filtering if specified
|
30
36
|
tables = options[:tables]
|
31
37
|
|
data/lib/rails-nl2sql.rb
ADDED
data/rails-nl2sql.gemspec
CHANGED
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.require_paths = ["lib"]
|
38
38
|
|
39
39
|
spec.add_dependency "openai", "~> 0.3"
|
40
|
-
spec.add_development_dependency "bundler", "
|
40
|
+
spec.add_development_dependency "bundler", ">= 2.0"
|
41
41
|
spec.add_development_dependency "rake", "~> 10.0"
|
42
42
|
spec.add_development_dependency "rspec-rails", "~> 6.0"
|
43
43
|
spec.add_dependency "railties", ">= 6.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-nl2sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Russell Van Curen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: openai
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '2.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '2.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,6 +89,7 @@ executables: []
|
|
89
89
|
extensions: []
|
90
90
|
extra_rdoc_files: []
|
91
91
|
files:
|
92
|
+
- ".DS_Store"
|
92
93
|
- ".gitignore"
|
93
94
|
- Gemfile
|
94
95
|
- Gemfile.lock
|
@@ -99,7 +100,11 @@ files:
|
|
99
100
|
- bin/setup
|
100
101
|
- lib/generators/rails/nl2sql/install_generator.rb
|
101
102
|
- lib/generators/rails/nl2sql/templates/rails_nl2sql.rb
|
103
|
+
- lib/generators/rails_nl2sql/install/install_generator.rb
|
104
|
+
- lib/generators/rails_nl2sql/install/templates/rails_nl2sql.rb
|
105
|
+
- lib/rails-nl2sql.rb
|
102
106
|
- lib/rails/nl2sql.rb
|
107
|
+
- lib/rails/nl2sql/active_record_extension.rb
|
103
108
|
- lib/rails/nl2sql/query_generator.rb
|
104
109
|
- lib/rails/nl2sql/query_validator.rb
|
105
110
|
- lib/rails/nl2sql/railtie.rb
|