1+ package com .microsoft .semantickernel .data .jdbc .oracle ;
2+
3+ import com .fasterxml .jackson .databind .JsonNode ;
4+ import com .fasterxml .jackson .databind .ObjectMapper ;
5+ import com .microsoft .semantickernel .data .jdbc .JDBCVectorStoreQueryProvider ;
6+ import com .microsoft .semantickernel .data .jdbc .postgres .PostgreSQLVectorStoreQueryProvider ;
7+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordDefinition ;
8+ import com .microsoft .semantickernel .data .vectorstorage .options .UpsertRecordOptions ;
9+ import com .microsoft .semantickernel .exceptions .SKException ;
10+ import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
11+
12+ import javax .annotation .Nonnull ;
13+ import javax .sql .DataSource ;
14+ import java .sql .Connection ;
15+ import java .sql .PreparedStatement ;
16+ import java .sql .SQLException ;
17+ import java .util .List ;
18+
19+ public class OracleVectorStoreQueryProvider extends JDBCVectorStoreQueryProvider {
20+
21+ // This could be removed if super.collectionTable made protected
22+ private final String collectionsTable ;
23+
24+ // This could be common to all query providers
25+ private final ObjectMapper objectMapper ;
26+
27+ private OracleVectorStoreQueryProvider (@ Nonnull DataSource dataSource , @ Nonnull String collectionsTable , @ Nonnull String prefixForCollectionTables ,
28+ ObjectMapper objectMapper ) {
29+ super (dataSource , collectionsTable , prefixForCollectionTables );
30+ this .collectionsTable = collectionsTable ;
31+ this .objectMapper = objectMapper ;
32+ }
33+
34+ @ Override
35+ public void prepareVectorStore () {
36+ String createCollectionsTable = formatQuery (
37+ "CREATE TABLE IF NOT EXISTS %s (collectionId VARCHAR(255) PRIMARY KEY)" ,
38+ validateSQLidentifier (collectionsTable ));
39+
40+ try (Connection connection = dataSource .getConnection ();
41+ PreparedStatement createTable = connection .prepareStatement (createCollectionsTable )) {
42+ createTable .execute ();
43+ } catch (SQLException e ) {
44+ throw new SKException ("Failed to prepare vector store" , e );
45+ }
46+ }
47+
48+ @ Override
49+ public void createCollection (String collectionName ,
50+ VectorStoreRecordDefinition recordDefinition ) {
51+ // TODO Override implementation. Eg: mapping TEXT to VARCHAR
52+ super .createCollection (collectionName , recordDefinition );
53+ }
54+
55+ @ Override
56+ public void upsertRecords (String collectionName , List <?> records , VectorStoreRecordDefinition recordDefinition , UpsertRecordOptions options ) {
57+
58+ // TODO look for public void createCollection(String collectionName, VectorStoreRecordDefinition recordDefinition) {
59+
60+ // TODO Make this a MERGE query
61+
62+ // String upsertStatemente = formatQuery("""
63+ // MERGE INTO %s EXIST_REC USING (SELECT ? AS ID) NEW_REC ON (EXIST_REC.%s = NEW_REC.ID)
64+ // WHEN MATACHED THEN UPDATE SET EXISTING REC
65+ // """,
66+ // getCollectionTableName(collectionName),
67+ // recordDefinition.getKeyField().getName(),
68+ // getQueryColumnsFromFields(fields),
69+ // getWildcardString(fields.size()),
70+ // onDuplicateKeyUpdate);super.upsertRecords(collectionName, records, recordDefinition, options);
71+
72+ String query = formatQuery ("INSERT INTO %s (%s, %s, %s) values (?, ?, ?)" ,
73+ getCollectionTableName (collectionName ),
74+ recordDefinition .getAllFields ().get (0 ).getStorageName (),
75+ recordDefinition .getAllFields ().get (1 ).getStorageName (),
76+ recordDefinition .getAllFields ().get (2 ).getStorageName ());
77+
78+ try (Connection connection = dataSource .getConnection ();
79+ PreparedStatement statement = connection .prepareStatement (query )) {
80+ for (Object record : records ) {
81+ JsonNode jsonNode = objectMapper .valueToTree (record );
82+ for (int i = 0 ; i < 3 ; i ++) {
83+ statement .setObject (i + 1 , jsonNode
84+ .get (recordDefinition .getAllFields ().get (i ).getStorageName ()).asText ());
85+ }
86+ statement .addBatch ();
87+ }
88+ statement .executeBatch ();
89+ } catch (SQLException e ) {
90+ throw new SKException ("Failed to upsert records" , e );
91+ }
92+ }
93+
94+ public static Builder builder () {
95+ return new Builder ();
96+ }
97+
98+ public static class Builder
99+ extends JDBCVectorStoreQueryProvider .Builder {
100+
101+ private DataSource dataSource ;
102+ private String collectionsTable = DEFAULT_COLLECTIONS_TABLE ;
103+ private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES ;
104+ private ObjectMapper objectMapper = new ObjectMapper ();
105+
106+ @ SuppressFBWarnings ("EI_EXPOSE_REP2" )
107+ public Builder withDataSource (DataSource dataSource ) {
108+ this .dataSource = dataSource ;
109+ return this ;
110+ }
111+
112+ /**
113+ * Sets the collections table name.
114+ * @param collectionsTable the collections table name
115+ * @return the builder
116+ */
117+ public Builder withCollectionsTable (String collectionsTable ) {
118+ this .collectionsTable = validateSQLidentifier (collectionsTable );
119+ return this ;
120+ }
121+
122+ /**
123+ * Sets the prefix for collection tables.
124+ * @param prefixForCollectionTables the prefix for collection tables
125+ * @return the builder
126+ */
127+ public Builder withPrefixForCollectionTables (String prefixForCollectionTables ) {
128+ this .prefixForCollectionTables = validateSQLidentifier (prefixForCollectionTables );
129+ return this ;
130+ }
131+
132+ public Builder withObjectMapper (
133+ ObjectMapper objectMapper ) {
134+ this .objectMapper = objectMapper ;
135+ return this ;
136+ }
137+
138+ @ Override
139+ public OracleVectorStoreQueryProvider build () {
140+ return new OracleVectorStoreQueryProvider (dataSource , collectionsTable ,
141+ prefixForCollectionTables , objectMapper );
142+ }
143+ }
144+ }
0 commit comments