Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ gem 'good_job', '~> 4.0'
gem 'rotp'

gem 'grpc', '~> 1.67'
gem 'tucana', '0.0.52'
gem 'tucana', '0.0.53'

gem 'code0-identities', '~> 0.0.3'

Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ GEM
thor (1.4.0)
timeout (0.6.0)
tsort (0.2.0)
tucana (0.0.52)
tucana (0.0.53)
grpc (~> 1.64)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -431,7 +431,7 @@ DEPENDENCIES
simplecov (~> 0.22.0)
simplecov-cobertura (~> 3.0)
test-prof (~> 1.0)
tucana (= 0.0.52)
tucana (= 0.0.53)
tzinfo-data

RUBY VERSION
Expand Down
15 changes: 13 additions & 2 deletions app/graphql/types/input/reference_value_input_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ class ReferenceValueInputType < Types::BaseInputObject
description 'Input type for reference value'

argument :reference_path, [Types::Input::ReferencePathInputType],
required: true, description: 'The paths associated with this reference value'
required: true,
description: 'The paths associated with this reference value'

argument :node_function_id, GlobalIdType[::NodeFunction], required: true, description: 'The referenced value'
argument :node_function_id, GlobalIdType[::NodeFunction],
required: false,
description: 'The referenced value unless referencing the flow input'

argument :parameter_index, GraphQL::Types::Int,
required: false,
description: 'The index of the referenced parameter'

argument :input_index, GraphQL::Types::Int,
required: false,
description: 'The index of the referenced input'
end
end
end
14 changes: 12 additions & 2 deletions app/graphql/types/reference_value_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,28 @@ module Types
class ReferenceValueType < Types::BaseObject
description 'Represents a reference value in the system.'

field :node_function_id, GlobalIdType[::NodeFunction], null: false, description: 'The referenced value.'
field :node_function_id, GlobalIdType[::NodeFunction],
null: true,
description: 'The referenced value unless referencing the flow input.'

field :reference_path, [Types::ReferencePathType],
null: false,
description: 'The paths associated with this reference value.',
method: :reference_paths

field :parameter_index, GraphQL::Types::Int,
null: true,
description: 'The index of the referenced parameter'

field :input_index, GraphQL::Types::Int,
null: true,
description: 'The index of the referenced input'

id_field ReferenceValue
timestamps

def node_function_id
object.node_function.to_global_id
object.node_function&.to_global_id
end
end
end
4 changes: 2 additions & 2 deletions app/models/flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def to_grpc
project_slug: project.slug,
type: flow_type.identifier,
data_types: [], # TODO: when data types are creatable
input_type_identifier: input_type&.identifier,
return_type_identifier: return_type&.identifier,
input_type: Tucana::Shared::DataTypeIdentifier.from_hash({ data_type_identifier: input_type&.identifier }),
return_type: Tucana::Shared::DataTypeIdentifier.from_hash({ data_type_identifier: return_type&.identifier }),
settings: flow_settings.map(&:to_grpc),
starting_node_id: starting_node.id,
node_functions: node_functions.map(&:to_grpc)
Expand Down
29 changes: 26 additions & 3 deletions app/models/reference_value.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
# frozen_string_literal: true

class ReferenceValue < ApplicationRecord
belongs_to :node_function # real value association
belongs_to :node_function, optional: true # real value association
has_many :reference_paths, inverse_of: :reference_value, autosave: true, dependent: :destroy
has_many :node_parameters, inverse_of: :reference_value

validate :validate_indexes

def validate_indexes
return if parameter_index.nil? && input_index.nil?

errors.add(:node_function, :blank) if node_function.nil?
errors.add(:input_index, :blank) if parameter_index.present? && input_index.nil?
errors.add(:parameter_index, :blank) if input_index.present? && parameter_index.nil?
end

def to_grpc
Tucana::Shared::ReferenceValue.new(
node_id: node_function.id,
reference_value = Tucana::Shared::ReferenceValue.new(
paths: reference_paths.map(&:to_grpc)
)

if node_function.nil?
reference_value.flow_input = Tucana::Shared::FlowInput.new
elsif parameter_index.present? && input_index.present?
reference_value.input_type = Tucana::Shared::InputType.new(
node_id: node_function.id,
parameter_index: parameter_index,
input_index: input_index
)
else
reference_value.node_id = node_function.id
end

reference_value
end
end
26 changes: 16 additions & 10 deletions app/services/namespaces/projects/flows/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,15 +202,19 @@ def update_node_parameters(t, current_node, current_node_input, all_nodes)
end

if parameter.value.reference_value.present?
referenced_node = all_nodes.find do |n|
n[:input].id == parameter.value.reference_value.node_function_id
end

if referenced_node.nil?
t.rollback_and_return! ServiceResponse.error(
message: 'Referenced node function not found',
error_code: :referenced_value_not_found
)
if parameter.value.reference_value.node_function_id.present?
referenced_node = all_nodes.find do |n|
n[:input].id == parameter.value.reference_value.node_function_id
end

if referenced_node.nil?
t.rollback_and_return! ServiceResponse.error(
message: 'Referenced node function not found',
error_code: :referenced_value_not_found
)
end
else
referenced_node = { node: nil }
end

db_parameters[index].reference_value ||= ReferenceValue.new
Expand All @@ -225,7 +229,9 @@ def update_node_parameters(t, current_node, current_node_input, all_nodes)

reference_value.assign_attributes(
node_function: referenced_node[:node],
reference_paths: reference_paths
reference_paths: reference_paths,
parameter_index: parameter.value.reference_value.parameter_index,
input_index: parameter.value.reference_value.input_index
)
else
db_parameters[index].reference_value&.destroy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class AddInputTypeFieldsToReferenceValue < Code0::ZeroTrack::Database::Migration[1.0]
def change
add_column :reference_values, :parameter_index, :int
add_column :reference_values, :input_index, :int

add_check_constraint :reference_values, 'num_nonnulls(parameter_index, input_index) IN (0, 2)',
name: check_constraint_name(:reference_values, :indexes, :none_or_both)

change_column_null :reference_values, :node_function_id, true
end
end
1 change: 1 addition & 0 deletions db/schema_migrations/20260222154501
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
12fbf843d279b87a5a6da04d17a2ccb718a18979fe6eaeb53ed76e7ad131fb17
5 changes: 4 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,10 @@ CREATE TABLE reference_values (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
node_function_id bigint NOT NULL
node_function_id bigint,
parameter_index integer,
input_index integer,
CONSTRAINT check_a2e3734389 CHECK ((num_nonnulls(parameter_index, input_index) = ANY (ARRAY[0, 2])))
);

CREATE SEQUENCE reference_values_id_seq
Expand Down
4 changes: 3 additions & 1 deletion docs/graphql/input_object/referencevalueinput.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ Input type for reference value

| Name | Type | Description |
|------|------|-------------|
| `nodeFunctionId` | [`NodeFunctionID!`](../scalar/nodefunctionid.md) | The referenced value |
| `inputIndex` | [`Int`](../scalar/int.md) | The index of the referenced input |
| `nodeFunctionId` | [`NodeFunctionID`](../scalar/nodefunctionid.md) | The referenced value unless referencing the flow input |
| `parameterIndex` | [`Int`](../scalar/int.md) | The index of the referenced parameter |
| `referencePath` | [`[ReferencePathInput!]!`](../input_object/referencepathinput.md) | The paths associated with this reference value |
4 changes: 3 additions & 1 deletion docs/graphql/object/referencevalue.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ Represents a reference value in the system.
|------|------|-------------|
| `createdAt` | [`Time!`](../scalar/time.md) | Time when this ReferenceValue was created |
| `id` | [`ReferenceValueID!`](../scalar/referencevalueid.md) | Global ID of this ReferenceValue |
| `nodeFunctionId` | [`NodeFunctionID!`](../scalar/nodefunctionid.md) | The referenced value. |
| `inputIndex` | [`Int`](../scalar/int.md) | The index of the referenced input |
| `nodeFunctionId` | [`NodeFunctionID`](../scalar/nodefunctionid.md) | The referenced value unless referencing the flow input. |
| `parameterIndex` | [`Int`](../scalar/int.md) | The index of the referenced parameter |
| `referencePath` | [`[ReferencePath!]!`](../object/referencepath.md) | The paths associated with this reference value. |
| `updatedAt` | [`Time!`](../scalar/time.md) | Time when this ReferenceValue was last updated |

2 changes: 2 additions & 0 deletions spec/factories/reference_values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
FactoryBot.define do
factory :reference_value do
node_function
parameter_index { nil }
input_index { nil }
end
end
2 changes: 2 additions & 0 deletions spec/models/flow_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
project_id: flow.project.id,
project_slug: flow.project.slug,
type: flow.flow_type.identifier,
input_type: {},
return_type: {},
node_functions: [
{
database_id: starting_node.id,
Expand Down
28 changes: 26 additions & 2 deletions spec/models/reference_value_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,36 @@
require 'rails_helper'

RSpec.describe ReferenceValue do
subject do
subject(:reference_value) do
create(:reference_value, node_function: create(:node_function))
end

describe 'associations' do
it { is_expected.to belong_to(:node_function) }
it { is_expected.to belong_to(:node_function).optional }
it { is_expected.to have_many(:reference_paths) }
end

describe 'validations' do
describe 'validate_indexes' do
it do
reference_value.parameter_index = 1
is_expected.not_to be_valid
end

it do
reference_value.input_index = 1
is_expected.not_to be_valid
end

it do
reference_value.parameter_index = 1
reference_value.input_index = 1
is_expected.to be_valid
end

it do
is_expected.to be_valid
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
id
path
}
parameterIndex
inputIndex
updatedAt
}
}
Expand Down Expand Up @@ -125,16 +127,33 @@
id: 'gid://sagittarius/NodeFunction/1001',
functionDefinitionId: function_definition.to_global_id.to_s,
parameters: [
parameterDefinitionId: function_definition.parameter_definitions.first.to_global_id.to_s,
value: {
referenceValue: {
referencePath: [
{
arrayIndex: 0,
path: 'some.path',
}
],
nodeFunctionId: 'gid://sagittarius/NodeFunction/2000',
{
parameterDefinitionId: function_definition.parameter_definitions.first.to_global_id.to_s,
value: {
referenceValue: {
referencePath: [
{
arrayIndex: 0,
path: 'some.path',
}
],
nodeFunctionId: 'gid://sagittarius/NodeFunction/2000',
parameterIndex: 1,
inputIndex: 1,
},
},
},
{
parameterDefinitionId: function_definition.parameter_definitions.first.to_global_id.to_s,
value: {
referenceValue: {
referencePath: [
{
arrayIndex: 1,
path: 'some.path',
}
],
},
},
}
],
Expand Down Expand Up @@ -181,9 +200,26 @@
:nodes,
:value
)
expect(parameter_values).to include(a_hash_including('value' => 100))
expect(parameter_values).to include(
a_hash_including('referencePath' => [a_hash_including('arrayIndex' => 0, 'path' => 'some.path')])
a_hash_including(
'__typename' => 'LiteralValue',
'value' => 100
)
)
expect(parameter_values).to include(
a_hash_including(
'__typename' => 'ReferenceValue',
'nodeFunctionId' => a_string_matching(%r{gid://sagittarius/NodeFunction/\d+}),
'referencePath' => [a_hash_including('arrayIndex' => 0, 'path' => 'some.path')],
'parameterIndex' => 1,
'inputIndex' => 1
)
)
expect(parameter_values).to include(
a_hash_including(
'__typename' => 'ReferenceValue',
'referencePath' => [a_hash_including('arrayIndex' => 1, 'path' => 'some.path')]
)
)

is_expected.to create_audit_event(
Expand Down