Skip to content

Commit 5aeeaa2

Browse files
committed
Optimise PrepareCommand to not use intermediate list, optimise Dapper commands to use Dictionary<string, object>
1 parent d52983c commit 5aeeaa2

1 file changed

Lines changed: 52 additions & 29 deletions

File tree

PowerSync/PowerSync.Common/MDSQLite/MDSQLiteConnection.cs

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ private static List<string> PrepareQueryString(ref string query, int parameterCo
115115
return parameterList;
116116
}
117117

118-
private static DynamicParameters? PrepareQuery(ref string query, object?[]? parameters)
118+
private static Dictionary<string, object?>? PrepareQuery(ref string query, object?[]? parameters)
119119
{
120120
if (parameters == null || parameters.Length == 0)
121121
{
@@ -125,36 +125,61 @@ private static List<string> PrepareQueryString(ref string query, int parameterCo
125125
int parameterCount = parameters.Length;
126126
var parameterNames = PrepareQueryString(ref query, parameterCount);
127127

128-
var dynamicParams = new DynamicParameters();
128+
var paramDict = new Dictionary<string, object?>(parameterCount);
129129

130130
for (int i = 0; i < parameterCount; i++)
131131
{
132-
dynamicParams.Add(parameterNames[i], parameters[i]);
132+
paramDict[parameterNames[i]] = parameters[i];
133133
}
134134

135-
return dynamicParams;
135+
return paramDict;
136136
}
137137

138-
private static List<string> PrepareCommandParameters(SqliteCommand command, ref string query, int parameterCount)
138+
private static void PrepareCommandParameters(SqliteCommand command, ref string query, int parameterCount)
139139
{
140-
var parameterNames = PrepareQueryString(ref query, parameterCount);
140+
if (parameterCount == 0)
141+
{
142+
command.CommandText = query;
143+
return;
144+
}
141145

142-
command.CommandText = query;
146+
int placeholderCount = query.Count(c => c == '?');
147+
if (placeholderCount != parameterCount)
148+
{
149+
throw new ArgumentException($"Number of parameters ({parameterCount}) does not match the number of `?` placeholders ({placeholderCount}) in the query.");
150+
}
143151

144-
foreach (var paramName in parameterNames)
152+
var sb = new StringBuilder();
153+
int lastPos = 0;
154+
int currentPos;
155+
for (int i = 0; i < parameterCount; i++)
145156
{
157+
currentPos = query.IndexOf('?', lastPos);
158+
159+
string paramName = $"@param{i}";
160+
161+
sb.Append(query, lastPos, currentPos - lastPos);
162+
sb.Append(paramName);
163+
146164
var parameter = command.CreateParameter();
147165
parameter.ParameterName = paramName;
148166
command.Parameters.Add(parameter);
167+
168+
lastPos = currentPos + 1;
149169
}
150170

151-
return parameterNames;
171+
if (lastPos < query.Length)
172+
{
173+
sb.Append(query, lastPos, query.Length - lastPos);
174+
}
175+
176+
command.CommandText = sb.ToString();
152177
}
153178

154179
private static void PrepareCommand(SqliteCommand command, ref string query, object?[]? parameters)
155180
{
156181
int parameterCount = parameters?.Length ?? 0;
157-
var parameterNames = PrepareCommandParameters(command, ref query, parameterCount);
182+
PrepareCommandParameters(command, ref query, parameterCount);
158183

159184
if (parameters != null)
160185
{
@@ -163,8 +188,6 @@ private static void PrepareCommand(SqliteCommand command, ref string query, obje
163188
command.Parameters[i].Value = parameters[i] ?? DBNull.Value;
164189
}
165190
}
166-
167-
command.CommandText = query;
168191
}
169192

170193
private static List<DynamicParameters>? PrepareQuery(ref string query, object?[][]? parameters)
@@ -182,7 +205,7 @@ private static void PrepareCommand(SqliteCommand command, ref string query, obje
182205

183206
var parameterNames = PrepareQueryString(ref query, parameterCount);
184207

185-
var dynamicParamsList = new List<DynamicParameters>();
208+
var preparedParamsList = new List<DynamicParameters>();
186209

187210
foreach (var paramSet in parameters)
188211
{
@@ -191,51 +214,51 @@ private static void PrepareCommand(SqliteCommand command, ref string query, obje
191214
throw new ArgumentException("Parameter sets have different number of arguments.");
192215
}
193216

194-
var dynamicParams = new DynamicParameters();
217+
var preparedParams = new DynamicParameters();
195218
for (int i = 0; i < parameterCount; i++)
196219
{
197-
dynamicParams.Add(parameterNames[i], paramSet[i]);
220+
preparedParams.Add(parameterNames[i], paramSet[i]);
198221
}
199-
dynamicParamsList.Add(dynamicParams);
222+
preparedParamsList.Add(preparedParams);
200223
}
201224

202-
return dynamicParamsList;
225+
return preparedParamsList;
203226
}
204227

205228
public Task<T[]> GetAll<T>(string query, object?[]? parameters = null)
206229
{
207-
DynamicParameters? dynamicParams = PrepareQuery(ref query, parameters);
208-
return Task.Run(async () => (await Db.QueryAsync<T>(query, dynamicParams, commandType: CommandType.Text)).ToArray());
230+
var preparedParams = PrepareQuery(ref query, parameters);
231+
return Task.Run(async () => (await Db.QueryAsync<T>(query, preparedParams, commandType: CommandType.Text)).ToArray());
209232
}
210233

211234
public Task<dynamic[]> GetAll(string query, object?[]? parameters = null)
212235
{
213-
DynamicParameters? dynamicParams = PrepareQuery(ref query, parameters);
214-
return Task.Run(async () => (await Db.QueryAsync(query, dynamicParams, commandType: CommandType.Text)).ToArray());
236+
var preparedParams = PrepareQuery(ref query, parameters);
237+
return Task.Run(async () => (await Db.QueryAsync(query, preparedParams, commandType: CommandType.Text)).ToArray());
215238
}
216239

217240
public Task<T?> GetOptional<T>(string query, object?[]? parameters = null)
218241
{
219-
DynamicParameters? dynamicParams = PrepareQuery(ref query, parameters);
220-
return Task.Run(() => Db.QueryFirstOrDefaultAsync<T>(query, dynamicParams, commandType: CommandType.Text));
242+
var preparedParams = PrepareQuery(ref query, parameters);
243+
return Task.Run(() => Db.QueryFirstOrDefaultAsync<T>(query, preparedParams, commandType: CommandType.Text));
221244
}
222245

223246
public Task<dynamic?> GetOptional(string query, object?[]? parameters = null)
224247
{
225-
DynamicParameters? dynamicParams = PrepareQuery(ref query, parameters);
226-
return Task.Run(() => Db.QueryFirstOrDefaultAsync(query, dynamicParams, commandType: CommandType.Text));
248+
var preparedParams = PrepareQuery(ref query, parameters);
249+
return Task.Run(() => Db.QueryFirstOrDefaultAsync(query, preparedParams, commandType: CommandType.Text));
227250
}
228251

229252
public Task<T> Get<T>(string query, object?[]? parameters = null)
230253
{
231-
DynamicParameters? dynamicParams = PrepareQuery(ref query, parameters);
232-
return Task.Run(() => Db.QueryFirstAsync<T>(query, dynamicParams, commandType: CommandType.Text));
254+
var preparedParams = PrepareQuery(ref query, parameters);
255+
return Task.Run(() => Db.QueryFirstAsync<T>(query, preparedParams, commandType: CommandType.Text));
233256
}
234257

235258
public Task<dynamic> Get(string query, object?[]? parameters = null)
236259
{
237-
DynamicParameters? dynamicParams = PrepareQuery(ref query, parameters);
238-
return Task.Run(() => Db.QueryFirstAsync(query, dynamicParams, commandType: CommandType.Text));
260+
var preparedParams = PrepareQuery(ref query, parameters);
261+
return Task.Run(() => Db.QueryFirstAsync(query, preparedParams, commandType: CommandType.Text));
239262
}
240263

241264
public Task<NonQueryResult> Execute(string query, object?[]? parameters = null) => Task.Run(() =>

0 commit comments

Comments
 (0)